update Angular to v20 #4

Merged
sandre merged 18 commits from feature/update-to-angular-v20 into master 2026-01-22 13:21:54 +00:00
73 changed files with 6648 additions and 11197 deletions

View File

@@ -345,6 +345,7 @@ namespace skydiveLogs_api.DomainBusiness
myStats.ForLastMonthByJumpType = resetStats.ForLastMonthByJumpType; myStats.ForLastMonthByJumpType = resetStats.ForLastMonthByJumpType;
myStats.ForLastYearByDz = resetStats.ForLastYearByDz; myStats.ForLastYearByDz = resetStats.ForLastYearByDz;
myStats.ForLastYearByJumpType = resetStats.ForLastYearByJumpType; myStats.ForLastYearByJumpType = resetStats.ForLastYearByJumpType;
myStats.ByYearByJumpType = resetStats.ByYearByJumpType;
_userStatsRepository.Update(myStats); _userStatsRepository.Update(myStats);
} }
@@ -358,8 +359,10 @@ namespace skydiveLogs_api.DomainBusiness
var allStats = _userStatsRepository.GetAll(_identityService.ConnectedUser); var allStats = _userStatsRepository.GetAll(_identityService.ConnectedUser);
if (allStats == null) if (allStats == null)
{ {
allStats = new UserStats(); allStats = new UserStats
allStats.User = _identityService.ConnectedUser; {
User = _identityService.ConnectedUser
};
_userStatsRepository.Add(allStats); _userStatsRepository.Add(allStats);
} }

View File

@@ -2,15 +2,17 @@
# Use the official Microsoft ASP.NET Core image to build the backend # Use the official Microsoft ASP.NET Core image to build the backend
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-backend FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-backend
WORKDIR "/src/backend" WORKDIR /src/backend
COPY Back/ . COPY Back .
RUN dotnet restore "skydiveLogs-api/skydiveLogs-api.csproj" RUN dotnet restore skydiveLogs-api/skydiveLogs-api.csproj
RUN dotnet publish "skydiveLogs-api/skydiveLogs-api.csproj" -c Release -o /app/publish RUN dotnet publish skydiveLogs-api/skydiveLogs-api.csproj -c Release -o /app/publish
# Use the official node image to build the Angular app # Use the official node image to build the Angular app
FROM node:20-alpine AS build-frontend FROM node:22-alpine AS build-frontend
WORKDIR /app WORKDIR /app
COPY ["Front/skydivelogs-app/package.json", "Front/skydivelogs-app/package-lock.json*", "./"] # COPY ["../Front/skydivelogs-app/package.json", "../Front/skydivelogs-app/package-lock.json*", "./"]
COPY Front/skydivelogs-app/package.json .
COPY Front/skydivelogs-app/package-lock.json .
RUN npm install RUN npm install
COPY --exclude=Front/skydivelogs-app/node_modules/* Front/skydivelogs-app/ . COPY --exclude=Front/skydivelogs-app/node_modules/* Front/skydivelogs-app/ .
RUN npm run build RUN npm run build
@@ -21,13 +23,12 @@ WORKDIR /app
# Install nginx # Install nginx
RUN apt-get update && apt-get install -y nginx curl && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y nginx curl && rm -rf /var/lib/apt/lists/*
# Copy custom nginx configuration # Copy custom nginx configuration
COPY nginx.conf /etc/nginx/sites-available/default COPY nginx.conf /etc/nginx/sites-available/default
RUN rm -rf /usr/share/nginx/html/* RUN rm -rf /usr/share/nginx/html/*
# Copy frontend dist folder to nginx html directory # Copy frontend dist folder to nginx html directory
COPY --from=build-frontend /app/dist/browser /usr/share/nginx/html COPY --from=build-frontend --exclude=/app/dist/browser/config/* /app/dist/browser /usr/share/nginx/html
RUN mkdir -p /usr/share/nginx/html/config
# Copy backend from the correct build stage # Copy backend from the correct build stage
COPY --from=build-backend /app/publish /app COPY --from=build-backend /app/publish /app

View File

@@ -4,7 +4,7 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
indent_style = space indent_style = space
indent_size = 2 indent_size = 4
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true

View File

@@ -15,7 +15,7 @@
"prefix": "app", "prefix": "app",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-angular:application", "builder": "@angular/build:application",
"options": { "options": {
"outputPath": "dist", "outputPath": "dist",
"index": "src/index.html", "index": "src/index.html",
@@ -26,11 +26,7 @@
"assets": [ "assets": [
"src/assets", "src/assets",
"src/config", "src/config",
"src/favicon.ico", "src/favicon.ico"
{
"glob": "**/*",
"input": "public"
}
], ],
"styles": [ "styles": [
"src/assets/css/styles-app-loading.scss", "src/assets/css/styles-app-loading.scss",
@@ -87,7 +83,7 @@
"defaultConfiguration": "production" "defaultConfiguration": "production"
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular/build:dev-server",
"configurations": { "configurations": {
"production": { "production": {
"buildTarget": "skydivelogs-app:build:production" "buildTarget": "skydivelogs-app:build:production"
@@ -99,10 +95,10 @@
"defaultConfiguration": "development" "defaultConfiguration": "development"
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n" "builder": "@angular/build:extract-i18n"
}, },
"test": { "test": {
"builder": "@angular-devkit/build-angular:karma", "builder": "@angular/build:karma",
"options": { "options": {
"polyfills": ["zone.js", "zone.js/testing"], "polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
@@ -119,5 +115,31 @@
} }
} }
} }
},
"schematics": {
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -5,23 +5,23 @@
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build --configuration production",
"test": "ng test", "test": "ng test",
"lint": "ng lint", "lint": "ng lint",
"e2e": "ng e2e" "e2e": "ng e2e"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^19.2.6", "@angular/animations": "^20.3.16",
"@angular/cdk": "^19.2.9", "@angular/cdk": "^20.2.14",
"@angular/common": "^19.2.6", "@angular/common": "^20.3.16",
"@angular/compiler": "^19.2.6", "@angular/compiler": "^20.3.16",
"@angular/core": "^19.2.6", "@angular/core": "^20.3.16",
"@angular/forms": "^19.2.6", "@angular/forms": "^20.3.16",
"@angular/material": "^19.2.9", "@angular/material": "^20.2.14",
"@angular/platform-browser": "^19.2.6", "@angular/platform-browser": "^20.3.16",
"@angular/platform-browser-dynamic": "^19.2.6", "@angular/platform-browser-dynamic": "^20.3.16",
"@angular/router": "^19.2.6", "@angular/router": "^20.3.16",
"@ngx-translate/core": "^17.0.0", "@ngx-translate/core": "^17.0.0",
"@ngx-translate/http-loader": "^17.0.0", "@ngx-translate/http-loader": "^17.0.0",
"chart.js": "^4.3.0", "chart.js": "^4.3.0",
@@ -31,9 +31,9 @@
"zone.js": "~0.15.0" "zone.js": "~0.15.0"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^19.2.7", "@angular/build": "^20.3.14",
"@angular/cli": "~19.2.7", "@angular/cli": "~20.3.14",
"@angular/compiler-cli": "^19.2.6", "@angular/compiler-cli": "^20.3.16",
"@types/jasmine": "~4.3.0", "@types/jasmine": "~4.3.0",
"jasmine-core": "~5.1.0", "jasmine-core": "~5.1.0",
"karma": "~6.4.0", "karma": "~6.4.0",
@@ -41,6 +41,6 @@
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0", "karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0", "karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.5.4" "typescript": "~5.9.3"
} }
} }

View File

@@ -1,33 +0,0 @@
import { inject, OnInit } from "@angular/core";
import { IconResolver, MatIconRegistry } from "@angular/material/icon";
import { DomSanitizer } from "@angular/platform-browser";
import { TranslateService } from "@ngx-translate/core";
import { ServiceComm } from "../services/service-comm.service";
@decorator
export class BaseComponent implements OnInit {
private titleId: string = "???";
protected serviceComm: ServiceComm;
protected translateService: TranslateService;
constructor(titleId: string) {
let iconRegistry = inject(MatIconRegistry);
let sanitizer = inject(DomSanitizer);
const resolver: IconResolver = (name) =>
sanitizer.bypassSecurityTrustResourceUrl(`/assets/icon/${name}.svg`);
iconRegistry.addSvgIconResolver(resolver);
this.serviceComm = inject(ServiceComm);
this.translateService = inject(TranslateService);
this.titleId = titleId;
}
ngOnInit() {
this.translateService.get(this.titleId).subscribe((data) => {
this.serviceComm.updatedComponentTitle(data);
// this.serviceComm.componentTitle.subscribe((title) => (this.title = data));
});
}
}
function decorator(target: typeof BaseComponent): void | typeof BaseComponent {}

View File

@@ -1,15 +1,3 @@
/* .hamburger__icon {
position: relative;
height: 1rem;
margin-right: 1rem;
cursor: pointer;
fill: #ffff;
}
.hamburger__icon__fill {
fill: #424242
} */
.navigation.side-menu-active { .navigation.side-menu-active {
left: 0px; left: 0px;
} }

View File

@@ -1,7 +1,9 @@
<mat-toolbar *ngIf="this.show()"> @if (this.show()) {
<mat-icon svgIcon="menu" (click)="snav.toggle()"></mat-icon> <mat-toolbar>
<h2>{{ translatedTitle }}</h2> <h2 (click)="snav.toggle()">
<mat-icon svgIcon="menu"></mat-icon>
{{ translatedTitle }}
</h2>
<mat-select <mat-select
[(value)]="selectedLanguageFlag" [(value)]="selectedLanguageFlag"
(selectionChange)="switchLang($event)" (selectionChange)="switchLang($event)"
@@ -20,7 +22,8 @@
<img src="assets/img/en.svg" style="width: 30px" /> <img src="assets/img/en.svg" style="width: 30px" />
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-toolbar> </mat-toolbar>
}
<mat-sidenav-container> <mat-sidenav-container>
<mat-sidenav #snav mode="over" style="padding: 0 20px 0 10px"> <mat-sidenav #snav mode="over" style="padding: 0 20px 0 10px">
@@ -153,7 +156,8 @@
>{{ "App_Nav_Gears" | translate }}</a >{{ "App_Nav_Gears" | translate }}</a
> >
</mat-nav-list> </mat-nav-list>
<mat-nav-list *ngIf="currentUser"> @if (currentUser) {
<mat-nav-list>
<hr class="splitter" /> <hr class="splitter" />
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
@@ -166,19 +170,25 @@
(click)="snav.toggle()" (click)="snav.toggle()"
skipLocationChange skipLocationChange
> >
{{ this.currentUser.firstName }} {{ this.currentUser.lastName }} {{ this.currentUser.firstName }}
{{ this.currentUser.lastName }}
</a> </a>
</mat-nav-list> </mat-nav-list>
<mat-nav-list *ngIf="currentUser"> }
@if (currentUser) {
<mat-nav-list>
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
aria-label="To logout" aria-label="To logout"
svgIcon="logout" svgIcon="logout"
></mat-icon> ></mat-icon>
<span (click)="snav.toggle(); logout()" style="cursor: pointer">{{ <span
"App_Nav_Logout" | translate (click)="snav.toggle(); logout()"
}}</span> style="cursor: pointer"
>{{ "App_Nav_Logout" | translate }}</span
>
</mat-nav-list> </mat-nav-list>
}
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content> <mat-sidenav-content>

View File

@@ -1,6 +1,6 @@
import { Component, inject, OnInit } from "@angular/core"; import { Component, inject, OnInit } from "@angular/core";
import { Router, RouterLink, RouterOutlet } from "@angular/router"; import { Router, RouterLink, RouterOutlet } from "@angular/router";
import { CommonModule } from "@angular/common";
import { DomSanitizer } from "@angular/platform-browser"; import { DomSanitizer } from "@angular/platform-browser";
import { MatToolbarModule } from "@angular/material/toolbar"; import { MatToolbarModule } from "@angular/material/toolbar";
import { import {
@@ -31,7 +31,6 @@ import { ServiceCacheApi } from "../services/service-cache-api.service";
templateUrl: "./app.component.html", templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"], styleUrls: ["./app.component.css"],
imports: [ imports: [
CommonModule,
MatToolbarModule, MatToolbarModule,
MatIconModule, MatIconModule,
MatSelectModule, MatSelectModule,
@@ -59,7 +58,9 @@ export class AppComponent implements OnInit {
) { ) {
const sanitizer = inject(DomSanitizer); const sanitizer = inject(DomSanitizer);
const resolver: IconResolver = (name) => const resolver: IconResolver = (name) =>
sanitizer.bypassSecurityTrustResourceUrl(`/assets/icon/${name}.svg`); sanitizer.bypassSecurityTrustResourceUrl(
`/assets/icon/${name}.svg`,
);
const iconRegistry = inject(MatIconRegistry); const iconRegistry = inject(MatIconRegistry);
iconRegistry.addSvgIconResolver(resolver); iconRegistry.addSvgIconResolver(resolver);
@@ -79,7 +80,8 @@ export class AppComponent implements OnInit {
}); });
} }
ngOnInit() { ngOnInit() {}
ngAfterViewInit() {
this.serviceComm.componentTitle.subscribe( this.serviceComm.componentTitle.subscribe(
(title) => (this.translatedTitle = title), (title) => (this.translatedTitle = title),
); );

View File

@@ -56,7 +56,9 @@ export const appConfig: ApplicationConfig = {
const initializerFn = initConfig(inject(ConfigurationHelper)); const initializerFn = initConfig(inject(ConfigurationHelper));
return initializerFn(); return initializerFn();
}), }),
provideHttpClient(withInterceptors([JwtAuthInterceptor, ErrorInterceptor])), provideHttpClient(
withInterceptors([JwtAuthInterceptor, ErrorInterceptor]),
),
provideCharts(withDefaultRegisterables()), provideCharts(withDefaultRegisterables()),
provideZoneChangeDetection({ eventCoalescing: true }), provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes), provideRouter(routes),

View File

@@ -6,13 +6,17 @@ export const routes: Routes = [
{ {
path: "", path: "",
loadComponent: () => loadComponent: () =>
import("./default/default.component").then((m) => m.DefaultComponent), import("./default/default.component").then(
(m) => m.DefaultComponent,
),
canActivate: [AuthGuardService], canActivate: [AuthGuardService],
}, },
{ {
path: "summary", path: "summary",
loadComponent: () => loadComponent: () =>
import("./summary/summary.component").then((m) => m.SummaryComponent), import("./summary/summary.component").then(
(m) => m.SummaryComponent,
),
canActivate: [AuthGuardService], canActivate: [AuthGuardService],
}, },
{ {
@@ -34,7 +38,9 @@ export const routes: Routes = [
{ {
path: "newjump", path: "newjump",
loadComponent: () => loadComponent: () =>
import("./new-jump/new-jump.component").then((m) => m.NewJumpComponent), import("./new-jump/new-jump.component").then(
(m) => m.NewJumpComponent,
),
canActivate: [AuthGuardService], canActivate: [AuthGuardService],
}, },
{ {

View File

@@ -7,98 +7,130 @@
> >
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>{{ "LoginCreateUser_Firstname" | translate }}</mat-label> <mat-label>{{ "CreateUser_Firstname" | translate }}</mat-label>
<input <input
type="text" type="text"
matInput matInput
#firstname="matInput" #firstname="matInput"
formControlName="firstname" formControlName="firstname"
[ngClass]="{ 'is-invalid': submitted && formCtrls['firstname'].errors }" [ngClass]="{
'is-invalid': submitted && formCtrls['firstname'].errors,
}"
tabindex="0" tabindex="0"
/> />
<mat-error *ngIf="formCtrls['firstname'].hasError('required')"> @if (formCtrls["firstname"].hasError("required")) {
{{ "LoginCreateUser_FirstnameRequired" | translate }} <mat-error>
{{ "CreateUser_FirstnameRequired" | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="formCtrls['firstname'].hasError('minlength')"> }
{{ "LoginCreateUser_FirstnamePattern" | translate }} @if (formCtrls["firstname"].hasError("minlength")) {
<mat-error>
{{ "CreateUser_FirstnamePattern" | translate }}
</mat-error> </mat-error>
}
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>{{ "LoginCreateUser_Lastname" | translate }}</mat-label> <mat-label>{{ "CreateUser_Lastname" | translate }}</mat-label>
<input <input
matInput matInput
type="text" type="text"
formControlName="lastname" formControlName="lastname"
[ngClass]="{ 'is-invalid': submitted && formCtrls['lastname'].errors }" [ngClass]="{
'is-invalid': submitted && formCtrls['lastname'].errors,
}"
tabindex="1" tabindex="1"
/> />
<mat-error *ngIf="formCtrls['lastname'].hasError('required')"> @if (formCtrls["lastname"].hasError("required")) {
{{ "LoginCreateUser_LastnameRequired" | translate }} <mat-error>
{{ "CreateUser_LastnameRequired" | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="formCtrls['lastname'].hasError('minlength')"> }
{{ "LoginCreateUser_LastnamePattern" | translate }} @if (formCtrls["lastname"].hasError("minlength")) {
<mat-error>
{{ "CreateUser_LastnamePattern" | translate }}
</mat-error> </mat-error>
}
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>{{ "LoginCreateUser_Email" | translate }}</mat-label> <mat-label>{{ "CreateUser_Email" | translate }}</mat-label>
<input <input
matInput matInput
type="email" type="email"
formControlName="email" formControlName="email"
[ngClass]="{ 'is-invalid': submitted && formCtrls['email'].errors }" [ngClass]="{
'is-invalid': submitted && formCtrls['email'].errors,
}"
tabindex="3" tabindex="3"
/> />
<mat-error *ngIf="formCtrls['email'].hasError('required')"> @if (formCtrls["email"].hasError("required")) {
{{ "LoginCreateUser_EmailRequired" | translate }} <mat-error>
{{ "CreateUser_EmailRequired" | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="formCtrls['email'].hasError('email')"> }
{{ "LoginCreateUser_EmailPattern" | translate }} @if (formCtrls["email"].hasError("email")) {
<mat-error>
{{ "CreateUser_EmailPattern" | translate }}
</mat-error> </mat-error>
}
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>{{ "LoginCreateUser_Username" | translate }}</mat-label> <mat-label>{{ "CreateUser_Username" | translate }}</mat-label>
<input <input
matInput matInput
type="text" type="text"
formControlName="username" formControlName="username"
[ngClass]="{ 'is-invalid': submitted && formCtrls['username'].errors }" [ngClass]="{
'is-invalid': submitted && formCtrls['username'].errors,
}"
tabindex="4" tabindex="4"
/> />
<mat-error *ngIf="formCtrls['username'].hasError('required')"> @if (formCtrls["username"].hasError("required")) {
{{ "LoginCreateUser_UsernameRequired" | translate }} <mat-error>
{{ "CreateUser_UsernameRequired" | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="formCtrls['username'].hasError('minlength')"> }
{{ "LoginCreateUser_UsernamePattern" | translate }} @if (formCtrls["username"].hasError("minlength")) {
<mat-error>
{{ "CreateUser_UsernamePattern" | translate }}
</mat-error> </mat-error>
}
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>{{ "LoginCreateUser_Password" | translate }}</mat-label> <mat-label>{{ "CreateUser_Password" | translate }}</mat-label>
<input <input
matInput matInput
type="password" type="password"
formControlName="password" formControlName="password"
[ngClass]="{ 'is-invalid': submitted && formCtrls['password'].errors }" [ngClass]="{
'is-invalid': submitted && formCtrls['password'].errors,
}"
tabindex="5" tabindex="5"
/> />
<mat-error *ngIf="formCtrls['password'].hasError('required')"> @if (formCtrls["password"].hasError("required")) {
{{ "LoginCreateUser_PasswordRequired" | translate }} <mat-error>
{{ "CreateUser_PasswordRequired" | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="formCtrls['password'].hasError('pattern')"> }
{{ "LoginCreateUser_PasswordPattern" | translate }} @if (formCtrls["password"].hasError("pattern")) {
<mat-error>
{{ "CreateUser_PasswordPattern" | translate }}
</mat-error> </mat-error>
}
</mat-form-field> </mat-form-field>
</p> </p>
<button [disabled]="!createForm.valid" mat-raised-button color="accent"> <button [disabled]="!createForm.valid" mat-raised-button color="accent">
{{ "LoginCreateUser_BtnLogin" | translate }} {{ "CreateUser_BtnLogin" | translate }}
</button> </button>
<div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{ error }}</div> @if (error) {
<div class="alert alert-danger mt-3 mb-0">{{ error }}</div>
}
</form> </form>

View File

@@ -30,5 +30,7 @@
</mat-form-field> </mat-form-field>
<br /> <br />
<button mat-raised-button color="accent" *ngIf="editMode">Update</button> @if (editMode) {
<button mat-raised-button color="accent">Update</button>
}
</form> </form>

View File

@@ -1,5 +1,5 @@
import { Component, Inject, OnInit } from "@angular/core"; import { Component, Inject, OnInit } from "@angular/core";
import { CommonModule } from "@angular/common";
import { MAT_DIALOG_DATA } from "@angular/material/dialog"; import { MAT_DIALOG_DATA } from "@angular/material/dialog";
import { TranslateModule } from "@ngx-translate/core"; import { TranslateModule } from "@ngx-translate/core";
import { MatCheckboxModule } from "@angular/material/checkbox"; import { MatCheckboxModule } from "@angular/material/checkbox";
@@ -20,7 +20,6 @@ import { ServiceComm } from "../../services/service-comm.service";
styleUrls: ["./jump-infos.component.css"], styleUrls: ["./jump-infos.component.css"],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
FormsModule, FormsModule,
MatCheckboxModule, MatCheckboxModule,
MatFormFieldModule, MatFormFieldModule,
@@ -36,7 +35,7 @@ export class JumpInfosComponent implements OnInit {
constructor( constructor(
@Inject(MAT_DIALOG_DATA) public data: any, @Inject(MAT_DIALOG_DATA) public data: any,
private serviceJump: JumpService, private serviceJump: JumpService,
private serviceComm: ServiceComm private serviceComm: ServiceComm,
) { ) {
this.jump = new JumpResp(data.jump); this.jump = new JumpResp(data.jump);
this.editMode = data.editMode; this.editMode = data.editMode;
@@ -50,7 +49,7 @@ export class JumpInfosComponent implements OnInit {
this.jump.id, this.jump.id,
this.jump.isSpecial, this.jump.isSpecial,
this.jump.withCutaway, this.jump.withCutaway,
this.jump.notes this.jump.notes,
) )
.subscribe(() => { .subscribe(() => {
this.serviceComm.refreshData(AddAction.Jump); this.serviceComm.refreshData(AddAction.Jump);

View File

@@ -1,14 +1,15 @@
<div class="content"> <div class="content">
<div *ngIf="dataSourceTable != null; else loading"> @if (dataSourceTable != null) {
<div>
@if (isUserAdmin == true) {
<button <button
mat-raised-button mat-raised-button
color="accent" color="accent"
(click)="openDialogToAdd()" (click)="openDialogToAdd()"
*ngIf="isUserAdmin == true"
> >
{{ "ListAircrafts_Add" | translate }} {{ "ListAircrafts_Add" | translate }}
</button> </button>
}
<table mat-table [dataSource]="dataSourceTable"> <table mat-table [dataSource]="dataSourceTable">
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
@@ -16,14 +17,14 @@
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td> <td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListAircrafts_Header_Name" | translate }} {{ "ListAircrafts_Header_Name" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.name }}</td> <td mat-cell *matCellDef="let element">
{{ element.name }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="imageData"> <ng-container matColumnDef="imageData">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListAircrafts_Header_Image" | translate }} {{ "ListAircrafts_Header_Image" | translate }}
@@ -36,14 +37,18 @@
/> />
</td> </td>
</ng-container> </ng-container>
<tr
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> mat-header-row
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> *matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</div> </div>
<mat-paginator [length]="resultsLength" [pageSize]="10"></mat-paginator> } @else {
<ng-template #loading>
<mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner> <mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner>
</ng-template> }
<mat-paginator [length]="resultsLength" [pageSize]="10"></mat-paginator>
</div> </div>

View File

@@ -3,7 +3,7 @@ import { MatPaginator, MatPaginatorModule } from "@angular/material/paginator";
import { MatTableDataSource, MatTableModule } from "@angular/material/table"; import { MatTableDataSource, MatTableModule } from "@angular/material/table";
import { MatDialog } from "@angular/material/dialog"; import { MatDialog } from "@angular/material/dialog";
import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { CommonModule } from "@angular/common";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner"; import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { MatButtonModule } from "@angular/material/button"; import { MatButtonModule } from "@angular/material/button";
@@ -20,7 +20,6 @@ import { AircraftResp } from "../../models/aircraft";
styleUrls: ["./list-of-aircrafts.component.css"], styleUrls: ["./list-of-aircrafts.component.css"],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
MatPaginatorModule, MatPaginatorModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
MatTableModule, MatTableModule,
@@ -39,7 +38,7 @@ export class ListOfAircraftsComponent implements OnInit {
private serviceComm: ServiceComm, private serviceComm: ServiceComm,
private authenticationService: AuthenticationService, private authenticationService: AuthenticationService,
public dialog: MatDialog, public dialog: MatDialog,
private translateService: TranslateService private translateService: TranslateService,
) { ) {
this.isUserAdmin = this.isUserAdmin =
this.authenticationService.currentUserValue.roles === "admin"; this.authenticationService.currentUserValue.roles === "admin";
@@ -66,7 +65,9 @@ export class ListOfAircraftsComponent implements OnInit {
this.serviceApi.getListOfAircrafts().subscribe((data) => { this.serviceApi.getListOfAircrafts().subscribe((data) => {
setTimeout(() => { setTimeout(() => {
data.sort((a, b) => a.name.localeCompare(b.name)); data.sort((a, b) => a.name.localeCompare(b.name));
this.dataSourceTable = new MatTableDataSource<AircraftResp>(data); this.dataSourceTable = new MatTableDataSource<AircraftResp>(
data,
);
this.dataSourceTable.paginator = this.paginator; this.dataSourceTable.paginator = this.paginator;
this.resultsLength = data.length; this.resultsLength = data.length;
}, 500); }, 500);

View File

@@ -1,14 +1,15 @@
<div class="content"> <div class="content">
<div *ngIf="dataSourceTable != null; else loading"> @if (dataSourceTable != null) {
<div>
@if (isUserAdmin == true) {
<button <button
mat-raised-button mat-raised-button
color="accent" color="accent"
(click)="openDialogToAdd()" (click)="openDialogToAdd()"
*ngIf="isUserAdmin == true"
> >
{{ "ListDz_Add" | translate }} {{ "ListDz_Add" | translate }}
</button> </button>
}
<mat-form-field> <mat-form-field>
<mat-label>{{ "ListDz_Filter" | translate }}</mat-label> <mat-label>{{ "ListDz_Filter" | translate }}</mat-label>
<input <input
@@ -18,28 +19,37 @@
#input #input
/> />
</mat-form-field> </mat-form-field>
<table mat-table [dataSource]="dataSourceTable"> <table mat-table [dataSource]="dataSourceTable">
<ng-container matColumnDef="isfavorite"> <ng-container matColumnDef="isfavorite">
<th mat-header-cell *matHeaderCellDef style="min-width: 144px"></th> <th
<td mat-cell *matCellDef="let element" style="text-align: left"> mat-header-cell
*matHeaderCellDef
style="min-width: 144px"
></th>
<td
mat-cell
*matCellDef="let element"
style="text-align: left"
>
@if (element.isFavorite === true) {
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
aria-label="Favorite" aria-label="Favorite"
*ngIf="element.isFavorite === true"
(click)="removeToFavorite(element)" (click)="removeToFavorite(element)"
color="primary" color="primary"
style="cursor: pointer" style="cursor: pointer"
svgIcon="favorite" svgIcon="favorite"
></mat-icon> ></mat-icon>
}
@if (element.isFavorite === false) {
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
aria-label="Not favorite" aria-label="Not favorite"
*ngIf="element.isFavorite === false"
(click)="setToFavorite(element)" (click)="setToFavorite(element)"
style="cursor: pointer" style="cursor: pointer"
svgIcon="not_favorite" svgIcon="not_favorite"
></mat-icon> ></mat-icon>
}
<a href="http://{{ element.website }}" target="_blank"> <a href="http://{{ element.website }}" target="_blank">
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
@@ -51,9 +61,9 @@
<a <a
href="https://www.openstreetmap.org/?mlat={{ href="https://www.openstreetmap.org/?mlat={{
element.latitude element.latitude
}}&mlon={{ element.longitude }}#map=14/{{ element.latitude }}/{{ }}&mlon={{ element.longitude }}#map=14/{{
element.longitude element.latitude
}}" }}/{{ element.longitude }}"
target="_blank" target="_blank"
> >
<mat-icon <mat-icon
@@ -63,7 +73,8 @@
svgIcon="map" svgIcon="map"
></mat-icon> ></mat-icon>
</a> </a>
<a href="mailto:{{ element.email }}" *ngIf="element.email"> @if (element.email) {
<a href="mailto:{{ element.email }}">
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
aria-label="Contact mail of the DZ" aria-label="Contact mail of the DZ"
@@ -71,48 +82,57 @@
svgIcon="mail" svgIcon="mail"
></mat-icon> ></mat-icon>
</a> </a>
}
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListDz_Header_ID" | translate }} {{ "ListDz_Header_ID" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td> <td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListDz_Header_Name" | translate }} {{ "ListDz_Header_Name" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="spanWithBreakWord" [innerHTML]="element.name"></span> <span
class="spanWithBreakWord"
[innerHTML]="element.name"
></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="address"> <ng-container matColumnDef="address">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListDz_Header_Address" | translate }} {{ "ListDz_Header_Address" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="spanWithBreakWord" [innerHTML]="element.address"></span> <span
class="spanWithBreakWord"
[innerHTML]="element.address"
></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="type"> <ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListDz_Header_Type" | translate }} {{ "ListDz_Header_Type" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.type }}</td> <td mat-cell *matCellDef="let element">
{{ element.type }}
</td>
</ng-container> </ng-container>
<tr
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> mat-header-row
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> *matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</div> </div>
<mat-paginator [length]="resultsLength" [pageSize]="20"></mat-paginator> } @else {
<ng-template #loading>
<mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner> <mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner>
</ng-template> }
<mat-paginator [length]="resultsLength" [pageSize]="20"></mat-paginator>
</div> </div>

View File

@@ -3,7 +3,7 @@ import { MatPaginator, MatPaginatorModule } from "@angular/material/paginator";
import { MatTableDataSource, MatTableModule } from "@angular/material/table"; import { MatTableDataSource, MatTableModule } from "@angular/material/table";
import { MatDialog } from "@angular/material/dialog"; import { MatDialog } from "@angular/material/dialog";
import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { CommonModule } from "@angular/common";
import { MatIconModule } from "@angular/material/icon"; import { MatIconModule } from "@angular/material/icon";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner"; import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { MatFormFieldModule } from "@angular/material/form-field"; import { MatFormFieldModule } from "@angular/material/form-field";
@@ -24,7 +24,6 @@ import { NewDropZoneComponent } from "../new-drop-zone/new-drop-zone.component";
styleUrls: ["./list-of-dzs.component.css"], styleUrls: ["./list-of-dzs.component.css"],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
MatIconModule, MatIconModule,
MatPaginatorModule, MatPaginatorModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
@@ -52,7 +51,7 @@ export class ListOfDzsComponent implements OnInit {
private serviceComm: ServiceComm, private serviceComm: ServiceComm,
private authenticationService: AuthenticationService, private authenticationService: AuthenticationService,
public dialog: MatDialog, public dialog: MatDialog,
private translateService: TranslateService private translateService: TranslateService,
) { ) {
this.isUserAdmin = this.isUserAdmin =
this.authenticationService.currentUserValue.roles === "admin"; this.authenticationService.currentUserValue.roles === "admin";
@@ -81,9 +80,11 @@ export class ListOfDzsComponent implements OnInit {
data.sort( data.sort(
(a, b) => (a, b) =>
(b.isFavorite ? 1 : 0) - (a.isFavorite ? 1 : 0) || (b.isFavorite ? 1 : 0) - (a.isFavorite ? 1 : 0) ||
a.name.localeCompare(b.name) a.name.localeCompare(b.name),
);
this.dataSourceTable = new MatTableDataSource<DropZoneResp>(
data,
); );
this.dataSourceTable = new MatTableDataSource<DropZoneResp>(data);
this.dataSourceTable.paginator = this.paginator; this.dataSourceTable.paginator = this.paginator;
this.resultsLength = data.length; this.resultsLength = data.length;
}, 500); }, 500);

View File

@@ -1,9 +1,13 @@
<div class="content"> <div class="content">
<div *ngIf="dataSourceTable != null; else loading"> @if (dataSourceTable != null) {
<button mat-raised-button color="accent" (click)="openDialogToAdd()"> <div>
<button
mat-raised-button
color="accent"
(click)="openDialogToAdd()"
>
{{ "ListGears_Add" | translate }} {{ "ListGears_Add" | translate }}
</button> </button>
<table mat-table [dataSource]="dataSourceTable"> <table mat-table [dataSource]="dataSourceTable">
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
@@ -11,58 +15,74 @@
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td> <td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef style="min-width: 130px"> <th
mat-header-cell
*matHeaderCellDef
style="min-width: 130px"
>
{{ "ListGears_Header_Name" | translate }} {{ "ListGears_Header_Name" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.name }}</td> <td mat-cell *matCellDef="let element">
{{ element.name }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="manufacturer"> <ng-container matColumnDef="manufacturer">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListGears_Header_Manufacturer" | translate }} {{ "ListGears_Header_Manufacturer" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.manufacturer }}</td> <td mat-cell *matCellDef="let element">
{{ element.manufacturer }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="maxSize"> <ng-container matColumnDef="maxSize">
<th mat-header-cell *matHeaderCellDef style="min-width: 90px"> <th
mat-header-cell
*matHeaderCellDef
style="min-width: 90px"
>
{{ "ListGears_Header_CanopySize" | translate }} {{ "ListGears_Header_CanopySize" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
{{ element.minSize }} - {{ element.maxSize }} {{ element.minSize }} - {{ element.maxSize }}
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="aad"> <ng-container matColumnDef="aad">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListGears_Header_Aad" | translate }} {{ "ListGears_Header_Aad" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.aad }}</td> <td mat-cell *matCellDef="let element">
{{ element.aad }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="mainCanopy"> <ng-container matColumnDef="mainCanopy">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListGears_Header_Main" | translate }} {{ "ListGears_Header_Main" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.mainCanopy }}</td> <td mat-cell *matCellDef="let element">
{{ element.mainCanopy }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="reserveCanopy"> <ng-container matColumnDef="reserveCanopy">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListGears_Header_Reserve" | translate }} {{ "ListGears_Header_Reserve" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.reserveCanopy }}</td> <td mat-cell *matCellDef="let element">
{{ element.reserveCanopy }}
</td>
</ng-container> </ng-container>
<tr
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> mat-header-row
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> *matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</div> </div>
<mat-paginator [length]="resultsLength" [pageSize]="10"></mat-paginator> } @else {
<ng-template #loading>
<mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner> <mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner>
</ng-template> }
<mat-paginator [length]="resultsLength" [pageSize]="10"></mat-paginator>
</div> </div>

View File

@@ -3,7 +3,7 @@ import { MatPaginator, MatPaginatorModule } from "@angular/material/paginator";
import { MatTableDataSource, MatTableModule } from "@angular/material/table"; import { MatTableDataSource, MatTableModule } from "@angular/material/table";
import { MatDialog } from "@angular/material/dialog"; import { MatDialog } from "@angular/material/dialog";
import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { CommonModule } from "@angular/common";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner"; import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { MatButtonModule } from "@angular/material/button"; import { MatButtonModule } from "@angular/material/button";
@@ -19,7 +19,6 @@ import { NewGearComponent } from "../new-gear/new-gear.component";
styleUrls: ["./list-of-gears.component.css"], styleUrls: ["./list-of-gears.component.css"],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
MatPaginatorModule, MatPaginatorModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
MatTableModule, MatTableModule,
@@ -43,7 +42,7 @@ export class ListOfGearsComponent implements OnInit {
private serviceApi: GearService, private serviceApi: GearService,
private serviceComm: ServiceComm, private serviceComm: ServiceComm,
public dialog: MatDialog, public dialog: MatDialog,
private translateService: TranslateService private translateService: TranslateService,
) {} ) {}
ngOnInit() { ngOnInit() {

View File

@@ -31,22 +31,36 @@
</form> </form>
</div> </div>
<div *ngIf="resultsLength > 0"> @if (resultsLength > 0) {
<div>
<table mat-table [dataSource]="dataSourceTable"> <table mat-table [dataSource]="dataSourceTable">
<ng-container matColumnDef="comment"> <ng-container matColumnDef="comment">
<th mat-header-cell *matHeaderCellDef style="text-align: center"> <th
mat-header-cell
*matHeaderCellDef
style="text-align: center"
>
Comments Comments
</th> </th>
<td mat-cell *matCellDef="let element" style="text-align: left"> <td mat-cell *matCellDef="let element" style="text-align: left">
<span style="white-space: nowrap">{{ element.comment }}</span> <span style="white-space: nowrap">{{
element.comment
}}</span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="data"> <ng-container matColumnDef="data">
<th mat-header-cell *matHeaderCellDef style="text-align: center"> <th
mat-header-cell
*matHeaderCellDef
style="text-align: center"
>
Image Image
</th> </th>
<td mat-cell *matCellDef="let element" style="text-align: center"> <td
mat-cell
*matCellDef="let element"
style="text-align: center"
>
<img <img
src="{{ element.data }}" src="{{ element.data }}"
alt="image" alt="image"
@@ -56,13 +70,15 @@
/> />
</td> </td>
</ng-container> </ng-container>
<tr
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> mat-header-row
*matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
<mat-paginator [length]="resultsLength" [pageSize]="10"></mat-paginator> <mat-paginator [length]="resultsLength" [pageSize]="10"></mat-paginator>
</div> </div>
}
<div <div
class="imgmodal" class="imgmodal"

View File

@@ -95,7 +95,8 @@ export class ListOfImagesComponent implements OnInit {
if (!allowed_types.includes(file.type)) { if (!allowed_types.includes(file.type)) {
this.imageError = "Only Images are allowed ( JPG | PNG )"; this.imageError = "Only Images are allowed ( JPG | PNG )";
} else if (file.size > max_size) { } else if (file.size > max_size) {
this.imageError = "Maximum size allowed is " + max_size / 1000 + "Mb"; this.imageError =
"Maximum size allowed is " + max_size / 1000 + "Mb";
} else { } else {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = this.checkAndExtractDataToBase64.bind(this); reader.onload = this.checkAndExtractDataToBase64.bind(this);
@@ -115,7 +116,11 @@ export class ListOfImagesComponent implements OnInit {
if (img_height > max_height && img_width > max_width) { if (img_height > max_height && img_width > max_width) {
this.imageError = this.imageError =
"Maximum dimentions allowed " + max_height + "*" + max_width + "px"; "Maximum dimentions allowed " +
max_height +
"*" +
max_width +
"px";
} else { } else {
const imgBase64Path = e.target.result; const imgBase64Path = e.target.result;
this.selectedFile = imgBase64Path; this.selectedFile = imgBase64Path;

View File

@@ -1,14 +1,15 @@
<div class="content"> <div class="content">
<div *ngIf="dataSourceTable != null; else loading"> @if (dataSourceTable != null) {
<div>
@if (isUserAdmin == true) {
<button <button
mat-raised-button mat-raised-button
color="accent" color="accent"
(click)="openDialogToAdd()" (click)="openDialogToAdd()"
*ngIf="isUserAdmin == true"
> >
{{ "ListJumpType_Add" | translate }} {{ "ListJumpType_Add" | translate }}
</button> </button>
}
<table mat-table [dataSource]="dataSourceTable"> <table mat-table [dataSource]="dataSourceTable">
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
@@ -16,21 +17,26 @@
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.id }}</td> <td mat-cell *matCellDef="let element">{{ element.id }}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListJumpType_Header_Name" | translate }} {{ "ListJumpType_Header_Name" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.name }}</td> <td mat-cell *matCellDef="let element">
{{ element.name }}
</td>
</ng-container> </ng-container>
<tr
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> mat-header-row
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> *matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</div> </div>
<mat-paginator [length]="resultsLength" [pageSize]="20"></mat-paginator> } @else {
<ng-template #loading>
<mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner> <mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner>
</ng-template> }
<mat-paginator [length]="resultsLength" [pageSize]="20"></mat-paginator>
</div> </div>

View File

@@ -3,7 +3,7 @@ import { MatPaginator, MatPaginatorModule } from "@angular/material/paginator";
import { MatTableDataSource, MatTableModule } from "@angular/material/table"; import { MatTableDataSource, MatTableModule } from "@angular/material/table";
import { MatDialog } from "@angular/material/dialog"; import { MatDialog } from "@angular/material/dialog";
import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { CommonModule } from "@angular/common";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner"; import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { MatButtonModule } from "@angular/material/button"; import { MatButtonModule } from "@angular/material/button";
@@ -20,7 +20,6 @@ import { NewJumpTypeComponent } from "../new-jump-type/new-jump-type.component";
styleUrls: ["./list-of-jump-types.component.css"], styleUrls: ["./list-of-jump-types.component.css"],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
MatPaginatorModule, MatPaginatorModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
MatTableModule, MatTableModule,
@@ -39,7 +38,7 @@ export class ListOfJumpTypesComponent implements OnInit {
private serviceComm: ServiceComm, private serviceComm: ServiceComm,
private authenticationService: AuthenticationService, private authenticationService: AuthenticationService,
public dialog: MatDialog, public dialog: MatDialog,
private translateService: TranslateService private translateService: TranslateService,
) { ) {
this.isUserAdmin = this.isUserAdmin =
this.authenticationService.currentUserValue.roles === "admin"; this.authenticationService.currentUserValue.roles === "admin";
@@ -66,7 +65,9 @@ export class ListOfJumpTypesComponent implements OnInit {
this.serviceApi.getListOfJumpTypes().subscribe((data) => { this.serviceApi.getListOfJumpTypes().subscribe((data) => {
setTimeout(() => { setTimeout(() => {
data.sort((a, b) => a.name.localeCompare(b.name)); data.sort((a, b) => a.name.localeCompare(b.name));
this.dataSourceTable = new MatTableDataSource<JumpTypeResp>(data); this.dataSourceTable = new MatTableDataSource<JumpTypeResp>(
data,
);
this.dataSourceTable.paginator = this.paginator; this.dataSourceTable.paginator = this.paginator;
this.resultsLength = data.length; this.resultsLength = data.length;
}, 500); }, 500);

View File

@@ -11,10 +11,9 @@
</button> </button>
</div> </div>
<mat-progress-bar @if (isLoading) {
[mode]="'indeterminate'" <mat-progress-bar [mode]="'indeterminate'"></mat-progress-bar>
*ngIf="isLoading" }
></mat-progress-bar>
<div> <div>
<table mat-table [dataSource]="dataSourceTable"> <table mat-table [dataSource]="dataSourceTable">
@@ -47,7 +46,9 @@
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
aria-label="Special jump" aria-label="Special jump"
[style.visibility]="element.isSpecial ? 'visible' : 'hidden'" [style.visibility]="
element.isSpecial ? 'visible' : 'hidden'
"
svgIcon="celebration" svgIcon="celebration"
></mat-icon> ></mat-icon>
</td> </td>
@@ -59,7 +60,8 @@
</th> </th>
<td mat-cell *matCellDef="let element; let i = index"> <td mat-cell *matCellDef="let element; let i = index">
{{ {{
paginator.length - (paginator.pageIndex * paginator.pageSize + i) paginator.length -
(paginator.pageIndex * paginator.pageSize + i)
}} }}
</td> </td>
</ng-container> </ng-container>
@@ -84,7 +86,11 @@
> >
{{ "ListJump_Header_JumpType" | translate }} {{ "ListJump_Header_JumpType" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element" style="text-wrap: nowrap"> <td
mat-cell
*matCellDef="let element"
style="text-wrap: nowrap"
>
<span <span
class="smallSpanWithBreakWord" class="smallSpanWithBreakWord"
[innerHTML]="element.jumpType.name" [innerHTML]="element.jumpType.name"
@@ -120,7 +126,9 @@
<th mat-header-cell *matHeaderCellDef> <th mat-header-cell *matHeaderCellDef>
{{ "ListJump_Header_Id" | translate }} {{ "ListJump_Header_Id" | translate }}
</th> </th>
<td mat-cell *matCellDef="let element">{{ element.gear.name }}</td> <td mat-cell *matCellDef="let element">
{{ element.gear.name }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
@@ -151,7 +159,10 @@
</td> </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> <tr
mat-header-row
*matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</div> </div>

View File

@@ -63,7 +63,7 @@ export class ListOfJumpsComponent implements OnInit {
private serviceComm: ServiceComm, private serviceComm: ServiceComm,
public dialog: MatDialog, public dialog: MatDialog,
private translateService: TranslateService, private translateService: TranslateService,
private statsService: StatsService private statsService: StatsService,
) {} ) {}
ngAferViewInit(): void { ngAferViewInit(): void {

View File

@@ -11,10 +11,9 @@
</button> </button>
</div> </div>
<mat-progress-bar @if (isLoading) {
[mode]="'indeterminate'" <mat-progress-bar [mode]="'indeterminate'"></mat-progress-bar>
*ngIf="isLoading" }
></mat-progress-bar>
<mat-radio-group <mat-radio-group
[(ngModel)]="selectedPeriod" [(ngModel)]="selectedPeriod"
@@ -32,9 +31,11 @@
</mat-radio-group> </mat-radio-group>
<mat-nav-list> <mat-nav-list>
<mat-list-item matListItemLine *ngFor="let stat of stats"> @for (stat of stats; track stat) {
<mat-list-item matListItemLine>
<label>{{ stat.id }} : {{ stat.values }}</label> <label>{{ stat.id }} : {{ stat.values }}</label>
</mat-list-item> </mat-list-item>
}
</mat-nav-list> </mat-nav-list>
<div class="chart-container"> <div class="chart-container">
@@ -54,18 +55,17 @@
{{ "ListTunnelFlight_LoadTable" | translate }} {{ "ListTunnelFlight_LoadTable" | translate }}
</button> </button>
<table @if (dataSourceTable?.data.length) {
mat-table <table mat-table [dataSource]="dataSourceTable">
[dataSource]="dataSourceTable"
*ngIf="dataSourceTable?.data.length"
>
<ng-container matColumnDef="id"> <ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>ID</th> <th mat-header-cell *matHeaderCellDef>ID</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span class="smallSpanWithBreakWord" [innerHTML]="element.id"></span> <span
class="smallSpanWithBreakWord"
[innerHTML]="element.id"
></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="tunnel"> <ng-container matColumnDef="tunnel">
<th mat-header-cell *matHeaderCellDef>Tunnel</th> <th mat-header-cell *matHeaderCellDef>Tunnel</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
@@ -75,7 +75,6 @@
></span> ></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="jumpType"> <ng-container matColumnDef="jumpType">
<th mat-header-cell *matHeaderCellDef>Jump Type</th> <th mat-header-cell *matHeaderCellDef>Jump Type</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
@@ -85,7 +84,6 @@
></span> ></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="nbMinutes"> <ng-container matColumnDef="nbMinutes">
<th mat-header-cell *matHeaderCellDef>Minutes</th> <th mat-header-cell *matHeaderCellDef>Minutes</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
@@ -95,7 +93,6 @@
></span> ></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="notes"> <ng-container matColumnDef="notes">
<th mat-header-cell *matHeaderCellDef>Notes</th> <th mat-header-cell *matHeaderCellDef>Notes</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
@@ -105,20 +102,28 @@
></span> ></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="flightDate"> <ng-container matColumnDef="flightDate">
<th mat-header-cell *matHeaderCellDef>Date</th> <th mat-header-cell *matHeaderCellDef>Date</th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<span <span
class="smallSpanWithBreakWord" class="smallSpanWithBreakWord"
[innerHTML]="element.flightDate | date: 'yyyy-MM-dd'" [innerHTML]="
element.flightDate | date: 'yyyy-MM-dd'
"
></span> ></span>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef style="min-width: 80px"></th> <th
<td mat-cell *matCellDef="let element" style="text-align: left"> mat-header-cell
*matHeaderCellDef
style="min-width: 80px"
></th>
<td
mat-cell
*matCellDef="let element"
style="text-align: left"
>
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
aria-label="Delete this jump" aria-label="Delete this jump"
@@ -128,9 +133,15 @@
></mat-icon> ></mat-icon>
</td> </td>
</ng-container> </ng-container>
<tr
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> mat-header-row
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> *matHeaderRowDef="displayedColumns; sticky: true"
></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
}
</div> </div>
</div> </div>

View File

@@ -65,7 +65,7 @@ export class ListOfTunnelFlightsComponent implements OnInit {
private serviceComm: ServiceComm, private serviceComm: ServiceComm,
private serviceTunnelFlight: TunnelFlightService, private serviceTunnelFlight: TunnelFlightService,
private translateService: TranslateService, private translateService: TranslateService,
private dateService: DateService private dateService: DateService,
) {} ) {}
ngOnInit() { ngOnInit() {
@@ -124,7 +124,9 @@ export class ListOfTunnelFlightsComponent implements OnInit {
} }
private updateTitle() { private updateTitle() {
this.translateService.get("ListTunnelFlight_Title").subscribe((data) => { this.translateService
.get("ListTunnelFlight_Title")
.subscribe((data) => {
this.serviceComm.updatedComponentTitle(data); this.serviceComm.updatedComponentTitle(data);
}); });
} }
@@ -135,7 +137,10 @@ export class ListOfTunnelFlightsComponent implements OnInit {
// Get data to show in a table // Get data to show in a table
let endDate = new Date(); let endDate = new Date();
endDate.setHours(0, 0, 0, 0); endDate.setHours(0, 0, 0, 0);
let beginDate = this.computeBeginDateByPeriod(this.selectedPeriod, endDate); let beginDate = this.computeBeginDateByPeriod(
this.selectedPeriod,
endDate,
);
this.serviceTunnelFlight this.serviceTunnelFlight
.getTunnelFlights(beginDate, endDate) .getTunnelFlights(beginDate, endDate)
@@ -151,7 +156,10 @@ export class ListOfTunnelFlightsComponent implements OnInit {
// Get data to show in a table // Get data to show in a table
let endDate = new Date(); let endDate = new Date();
endDate.setHours(0, 0, 0, 0); endDate.setHours(0, 0, 0, 0);
let beginDate = this.computeBeginDateByPeriod(this.selectedPeriod, endDate); let beginDate = this.computeBeginDateByPeriod(
this.selectedPeriod,
endDate,
);
this.serviceTunnelFlight this.serviceTunnelFlight
.getTunnelFlightsByMonth(beginDate, endDate) .getTunnelFlightsByMonth(beginDate, endDate)
@@ -159,7 +167,7 @@ export class ListOfTunnelFlightsComponent implements OnInit {
const allMonths = this.getMontsBetweenDates(beginDate, endDate); const allMonths = this.getMontsBetweenDates(beginDate, endDate);
const cumulatedTime = this.getCumulatedTimeByTypeByMonth( const cumulatedTime = this.getCumulatedTimeByTypeByMonth(
data, data,
allMonths allMonths,
); );
this.computeTimeByType(data); this.computeTimeByType(data);
this.barChartData = { this.barChartData = {
@@ -177,12 +185,16 @@ export class ListOfTunnelFlightsComponent implements OnInit {
.pipe( .pipe(
groupBy((type) => type.type, { element: (p) => p.nb }), groupBy((type) => type.type, { element: (p) => p.nb }),
mergeMap((group$) => mergeMap((group$) =>
group$.pipe(reduce((acc, cur) => [...acc, cur], [`${group$.key}`])) group$.pipe(
reduce((acc, cur) => [...acc, cur], [`${group$.key}`]),
),
), ),
map((arr) => ({ map((arr) => ({
id: arr[0], id: arr[0],
values: arr.slice(1).reduce((a, b) => Number(a) + Number(b), 0), values: arr
})) .slice(1)
.reduce((a, b) => Number(a) + Number(b), 0),
})),
) )
.subscribe((p) => { .subscribe((p) => {
console.log(p); console.log(p);
@@ -190,7 +202,10 @@ export class ListOfTunnelFlightsComponent implements OnInit {
}); });
} }
private getMontsBetweenDates(beginDate: Date, endDate: Date): Array<string> { private getMontsBetweenDates(
beginDate: Date,
endDate: Date,
): Array<string> {
let results: Array<string> = []; let results: Array<string> = [];
let tmpBeginDate = new Date(beginDate.getTime()); let tmpBeginDate = new Date(beginDate.getTime());
const tmpEndDate = new Date(endDate.getTime()); const tmpEndDate = new Date(endDate.getTime());
@@ -205,15 +220,17 @@ export class ListOfTunnelFlightsComponent implements OnInit {
private getCumulatedTimeByTypeByMonth( private getCumulatedTimeByTypeByMonth(
stats: TunnelFlightByMonth[], stats: TunnelFlightByMonth[],
allMonths: string[] allMonths: string[],
): Array<any> { ): Array<any> {
let tmpResults = new Map<string, number[]>(); let tmpResults = new Map<string, number[]>();
const disctintType = Array.from(new Set(stats.map((item) => item.type))); const disctintType = Array.from(
new Set(stats.map((item) => item.type)),
);
disctintType.forEach((type) => { disctintType.forEach((type) => {
tmpResults.set( tmpResults.set(
type, type,
Array.from({ length: allMonths.length }, (v, k) => 0) Array.from({ length: allMonths.length }, (v, k) => 0),
); );
}); });
@@ -247,7 +264,7 @@ export class ListOfTunnelFlightsComponent implements OnInit {
private computeBeginDateByPeriod( private computeBeginDateByPeriod(
selectedPeriod: String, selectedPeriod: String,
endDate: Date endDate: Date,
): Date { ): Date {
let beginDate = new Date(); let beginDate = new Date();

View File

@@ -13,14 +13,20 @@
matInput matInput
#username="matInput" #username="matInput"
formControlName="username" formControlName="username"
[ngClass]="{ 'is-invalid': submitted && formCtrls['username'].errors }" [ngClass]="{
'is-invalid': submitted && formCtrls['username'].errors,
}"
/> />
<mat-error *ngIf="formCtrls['username'].hasError('required')"> @if (formCtrls["username"].hasError("required")) {
<mat-error>
{{ "LoginUser_UsernameRequired" | translate }} {{ "LoginUser_UsernameRequired" | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="formCtrls['username'].hasError('minlength')"> }
@if (formCtrls["username"].hasError("minlength")) {
<mat-error>
{{ 'LoginUser_UsernamePattern | translate }} {{ 'LoginUser_UsernamePattern | translate }}
</mat-error> </mat-error>
}
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
@@ -30,21 +36,31 @@
type="password" type="password"
matInput matInput
formControlName="password" formControlName="password"
[ngClass]="{ 'is-invalid': submitted && formCtrls['password'].errors }" [ngClass]="{
'is-invalid': submitted && formCtrls['password'].errors,
}"
/> />
<mat-error *ngIf="formCtrls['password'].hasError('required')"> @if (formCtrls["password"].hasError("required")) {
<mat-error>
{{ "LoginUser_PasswordRequired" | translate }} {{ "LoginUser_PasswordRequired" | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="formCtrls['password'].hasError('pattern')"> }
@if (formCtrls["password"].hasError("pattern")) {
<mat-error>
{{ "LoginUser_PasswordPattern" | translate }} {{ "LoginUser_PasswordPattern" | translate }}
</mat-error> </mat-error>
}
</mat-form-field> </mat-form-field>
</p> </p>
<button [disabled]="loading" mat-raised-button color="accent"> <button [disabled]="loading" mat-raised-button color="accent">
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span> @if (loading) {
<span class="spinner-border spinner-border-sm mr-1"></span>
}
{{ "LoginUser_BtnLogin" | translate }} {{ "LoginUser_BtnLogin" | translate }}
</button> </button>
<div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{ error }}</div> @if (error) {
<div class="alert alert-danger mt-3 mb-0">{{ error }}</div>
}
</form> </form>

View File

@@ -41,7 +41,7 @@ export class LoginUserComponent implements OnInit {
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
private authenticationService: AuthenticationService private authenticationService: AuthenticationService,
) { ) {
if (this.authenticationService.currentUserValue) { if (this.authenticationService.currentUserValue) {
this.router.navigate(["/"]); this.router.navigate(["/"]);
@@ -54,7 +54,7 @@ export class LoginUserComponent implements OnInit {
username: ["", [Validators.required, Validators.minLength(3)]], username: ["", [Validators.required, Validators.minLength(3)]],
password: ["", [Validators.required]], password: ["", [Validators.required]],
}, },
{ updateOn: "submit" } { updateOn: "submit" },
); );
// get return url from route parameters or default to '/' // get return url from route parameters or default to '/'
@@ -73,7 +73,7 @@ export class LoginUserComponent implements OnInit {
this.authenticationService this.authenticationService
.login( .login(
this.formCtrls["username"].value, this.formCtrls["username"].value,
this.formCtrls["password"].value this.formCtrls["password"].value,
) )
.pipe(first()) .pipe(first())
.subscribe({ .subscribe({

View File

@@ -16,7 +16,9 @@
> >
<mat-select-trigger> <mat-select-trigger>
<img <img
src="{{ 'assets/img/' + selectedLanguageFlag + '.svg' }}" src="{{
'assets/img/' + selectedLanguageFlag + '.svg'
}}"
style="width: 30px" style="width: 30px"
/> />
</mat-select-trigger> </mat-select-trigger>
@@ -31,10 +33,16 @@
<mat-card-content> <mat-card-content>
<mat-tab-group mat-align-tabs="center" animationDuration="0ms"> <mat-tab-group mat-align-tabs="center" animationDuration="0ms">
<mat-tab label="{{ 'Login_Tab_WithUser' | translate }}" tabIndex="-1"> <mat-tab
label="{{ 'Login_Tab_WithUser' | translate }}"
tabIndex="-1"
>
<app-login-user></app-login-user> <app-login-user></app-login-user>
</mat-tab> </mat-tab>
<mat-tab label="{{ 'Login_Tab_CreateUser' | translate }}" tabIndex="-1"> <mat-tab
label="{{ 'Login_Tab_CreateUser' | translate }}"
tabIndex="-1"
>
<app-create-user></app-create-user> <app-create-user></app-create-user>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>

View File

@@ -4,7 +4,7 @@ import {
TranslatePipe, TranslatePipe,
TranslateService, TranslateService,
} from "@ngx-translate/core"; } from "@ngx-translate/core";
import { CommonModule } from "@angular/common";
import { MatSelectModule } from "@angular/material/select"; import { MatSelectModule } from "@angular/material/select";
import { MatOptionModule } from "@angular/material/core"; import { MatOptionModule } from "@angular/material/core";
import { MatCardModule } from "@angular/material/card"; import { MatCardModule } from "@angular/material/card";
@@ -19,7 +19,6 @@ import { CreateUserComponent } from "../create-user/create-user.component";
styleUrls: ["./login.component.css"], styleUrls: ["./login.component.css"],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
MatSelectModule, MatSelectModule,
MatOptionModule, MatOptionModule,
MatCardModule, MatCardModule,

View File

@@ -3,12 +3,19 @@
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Aircraft name</mat-label> <mat-label>Aircraft name</mat-label>
<input matInput type="text" formControlName="aircraftName"> <input matInput type="text" formControlName="aircraftName" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<input type="file" #fileUpload id="fileUpload" name="fileUpload" accept="image/*" formControlName="image" <input
(change)="onFileChanged($event)" /> type="file"
#fileUpload
id="fileUpload"
name="fileUpload"
accept="image/*"
formControlName="image"
(change)="onFileChanged($event)"
/>
</p> </p>
<button type="submit" mat-raised-button color="accent">Add</button> <button type="submit" mat-raised-button color="accent">Add</button>

View File

@@ -79,7 +79,8 @@ export class NewAircraftComponent implements OnInit {
if (!allowed_types.includes(file.type)) { if (!allowed_types.includes(file.type)) {
this.imageError = "Only Images are allowed ( JPG | PNG )"; this.imageError = "Only Images are allowed ( JPG | PNG )";
} else if (file.size > max_size) { } else if (file.size > max_size) {
this.imageError = "Maximum size allowed is " + max_size / 1000 + "Mb"; this.imageError =
"Maximum size allowed is " + max_size / 1000 + "Mb";
} else { } else {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = this.checkAndExtractDataToBase64.bind(this); reader.onload = this.checkAndExtractDataToBase64.bind(this);
@@ -99,7 +100,11 @@ export class NewAircraftComponent implements OnInit {
if (img_height > max_height && img_width > max_width) { if (img_height > max_height && img_width > max_width) {
this.imageError = this.imageError =
"Maximum dimentions allowed " + max_height + "*" + max_width + "px"; "Maximum dimentions allowed " +
max_height +
"*" +
max_width +
"px";
} else { } else {
const imgBase64Path = e.target.result; const imgBase64Path = e.target.result;
this.selectedFile = imgBase64Path; this.selectedFile = imgBase64Path;

View File

@@ -3,43 +3,43 @@
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Name of gear</mat-label> <mat-label>Name of gear</mat-label>
<input matInput type="text" formControlName="name"> <input matInput type="text" formControlName="name" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Manufacturer</mat-label> <mat-label>Manufacturer</mat-label>
<input matInput type="text" formControlName="manufacturer"> <input matInput type="text" formControlName="manufacturer" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Min size of canopy</mat-label> <mat-label>Min size of canopy</mat-label>
<input matInput type="text" formControlName="minSize"> <input matInput type="text" formControlName="minSize" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Max size of canopy</mat-label> <mat-label>Max size of canopy</mat-label>
<input matInput type="text" formControlName="maxSize"> <input matInput type="text" formControlName="maxSize" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>AAD system</mat-label> <mat-label>AAD system</mat-label>
<input matInput type="text" formControlName="aad"> <input matInput type="text" formControlName="aad" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Main Canopy</mat-label> <mat-label>Main Canopy</mat-label>
<input matInput type="text" formControlName="mainCanopy"> <input matInput type="text" formControlName="mainCanopy" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Reserve canopy</mat-label> <mat-label>Reserve canopy</mat-label>
<input matInput type="text" formControlName="reserveCanopy"> <input matInput type="text" formControlName="reserveCanopy" />
</mat-form-field> </mat-form-field>
</p> </p>

View File

@@ -3,7 +3,7 @@
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Jump type name</mat-label> <mat-label>Jump type name</mat-label>
<input matInput type="text" formControlName="jumptypeName"> <input matInput type="text" formControlName="jumptypeName" />
</mat-form-field> </mat-form-field>
</p> </p>

View File

@@ -53,7 +53,9 @@ export class NewJumpTypeComponent implements OnInit {
} }
onSubmit(formData) { onSubmit(formData) {
this.jumpTypeService.addJumpType(formData.jumptypeName).subscribe(() => { this.jumpTypeService
.addJumpType(formData.jumptypeName)
.subscribe(() => {
this.serviceComm.refreshData(AddAction.JumpType); this.serviceComm.refreshData(AddAction.JumpType);
}); });
} }

View File

@@ -16,13 +16,12 @@
</p> </p>
</div> </div>
<form @if (notLoadingToDisplay()) {
class="formNewJumps" <form class="formNewJumps" (ngSubmit)="onFormSubmit()">
(ngSubmit)="onFormSubmit()"
*ngIf="notLoadingToDisplay(); else loading"
>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewJump_ChooseJumpType" | translate }}</mat-label> <mat-label>{{
"NewJump_ChooseJumpType" | translate
}}</mat-label>
<input <input
type="text" type="text"
matInput matInput
@@ -34,23 +33,27 @@
#autoJumpType="matAutocomplete" #autoJumpType="matAutocomplete"
[displayWith]="displayNameFn" [displayWith]="displayNameFn"
> >
<mat-option *ngFor="let jumpType of listOfJumpType" [value]="jumpType"> @for (jumpType of listOfJumpType; track jumpType) {
<mat-option [value]="jumpType">
{{ jumpType.name }} {{ jumpType.name }}
</mat-option> </mat-option>
}
</mat-autocomplete> </mat-autocomplete>
@if (selectedJumpType) {
<button <button
*ngIf="selectedJumpType"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="selectedJumpType = undefined" (click)="selectedJumpType = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewJump_ChooseAircraft" | translate }}</mat-label> <mat-label>{{
"NewJump_ChooseAircraft" | translate
}}</mat-label>
<input <input
type="text" type="text"
matInput matInput
@@ -62,21 +65,23 @@
#autoAircraft="matAutocomplete" #autoAircraft="matAutocomplete"
[displayWith]="displayNameFn" [displayWith]="displayNameFn"
> >
<mat-option *ngFor="let aircraft of listOfAircraft" [value]="aircraft"> @for (aircraft of listOfAircraft; track aircraft) {
<mat-option [value]="aircraft">
{{ aircraft.name }} {{ aircraft.name }}
</mat-option> </mat-option>
}
</mat-autocomplete> </mat-autocomplete>
@if (selectedAircraft) {
<button <button
*ngIf="selectedAircraft"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="selectedAircraft = undefined" (click)="selectedAircraft = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewJump_ChooseDz" | translate }}</mat-label> <mat-label>{{ "NewJump_ChooseDz" | translate }}</mat-label>
<input <input
@@ -91,32 +96,32 @@
#autoDropZone="matAutocomplete" #autoDropZone="matAutocomplete"
[displayWith]="displayNameFn" [displayWith]="displayNameFn"
> >
<mat-option @for (dropZone of listOfFilteredDropZone; track dropZone) {
*ngFor="let dropZone of listOfFilteredDropZone" <mat-option [value]="dropZone">
[value]="dropZone"
>
{{ dropZone.name }} {{ dropZone.name }}
@if (dropZone.isFavorite === true) {
<mat-icon <mat-icon
aria-hidden="false" aria-hidden="false"
aria-label="Favorite" aria-label="Favorite"
*ngIf="dropZone.isFavorite === true"
color="primary" color="primary"
svgIcon="favorite"
> >
favorite</mat-icon </mat-icon>
> }
</mat-option> </mat-option>
}
</mat-autocomplete> </mat-autocomplete>
@if (selectedDz) {
<button <button
*ngIf="selectedDz"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="resetDz()" (click)="resetDz()"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewJump_ChooseGear" | translate }}</mat-label> <mat-label>{{ "NewJump_ChooseGear" | translate }}</mat-label>
<input <input
@@ -130,28 +135,29 @@
#autoGear="matAutocomplete" #autoGear="matAutocomplete"
[displayWith]="displayGearFn" [displayWith]="displayGearFn"
> >
<mat-option *ngFor="let gear of listOfGear" [value]="gear"> @for (gear of listOfGear; track gear) {
<mat-option [value]="gear">
{{ gear.name }} ({{ gear.mainCanopy }}) {{ gear.name }} ({{ gear.mainCanopy }})
</mat-option> </mat-option>
}
</mat-autocomplete> </mat-autocomplete>
@if (selectedGear) {
<button <button
*ngIf="selectedGear"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="selectedGear = undefined" (click)="selectedGear = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-checkbox [(ngModel)]="withCutaway" name="withCutaway">{{ <mat-checkbox [(ngModel)]="withCutaway" name="withCutaway">{{
"NewJump_Cutaway" | translate "NewJump_Cutaway" | translate
}}</mat-checkbox> }}</mat-checkbox>
<mat-checkbox [(ngModel)]="isSpecial" name="isSpecial">{{ <mat-checkbox [(ngModel)]="isSpecial" name="isSpecial">{{
"NewJump_Special" | translate "NewJump_Special" | translate
}}</mat-checkbox> }}</mat-checkbox>
<mat-form-field> <mat-form-field>
<input <input
matInput matInput
@@ -167,7 +173,6 @@
></mat-datepicker-toggle> ></mat-datepicker-toggle>
<mat-datepicker #beginDateDp disabled="false"></mat-datepicker> <mat-datepicker #beginDateDp disabled="false"></mat-datepicker>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<input <input
matInput matInput
@@ -182,7 +187,6 @@
></mat-datepicker-toggle> ></mat-datepicker-toggle>
<mat-datepicker #endDateDp disabled="false"></mat-datepicker> <mat-datepicker #endDateDp disabled="false"></mat-datepicker>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<input <input
matInput matInput
@@ -191,15 +195,16 @@
name="exitAltitude" name="exitAltitude"
type="number" type="number"
/> />
@if (exitAltitude) {
<button <button
*ngIf="exitAltitude"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="exitAltitude = undefined" (click)="exitAltitude = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<input <input
@@ -209,17 +214,17 @@
name="deployAltitude" name="deployAltitude"
type="number" type="number"
/> />
@if (deployAltitude) {
<button <button
*ngIf="deployAltitude"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="deployAltitude = undefined" (click)="deployAltitude = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<input <input
matInput matInput
@@ -228,17 +233,17 @@
name="countOfJumps" name="countOfJumps"
type="number" type="number"
/> />
@if (countOfJumps) {
<button <button
*ngIf="countOfJumps"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="countOfJumps = undefined" (click)="countOfJumps = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<textarea <textarea
matInput matInput
@@ -247,24 +252,25 @@
name="comments" name="comments"
type="text" type="text"
></textarea> ></textarea>
@if (comments) {
<button <button
*ngIf="comments"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="comments = undefined" (click)="comments = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<br /> <br />
<button mat-raised-button color="accent" *ngIf="isValidatedForm()"> @if (this.isValidatedForm()) {
<button mat-raised-button color="accent">
{{ "NewJump_Submit" | translate }} {{ "NewJump_Submit" | translate }}
</button> </button>
}
</form> </form>
} @else {
<ng-template #loading>
<mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner> <mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner>
</ng-template> }
</div> </div>

View File

@@ -7,7 +7,7 @@ import {
NativeDateAdapter, NativeDateAdapter,
} from "@angular/material/core"; } from "@angular/material/core";
import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { CommonModule } from "@angular/common";
import { MatIconModule } from "@angular/material/icon"; import { MatIconModule } from "@angular/material/icon";
import { MatOptionModule } from "@angular/material/core"; import { MatOptionModule } from "@angular/material/core";
import { MatFormFieldModule } from "@angular/material/form-field"; import { MatFormFieldModule } from "@angular/material/form-field";
@@ -58,7 +58,6 @@ class PickDateAdapter extends NativeDateAdapter {
], ],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
RouterLink, RouterLink,
FormsModule, FormsModule,
RouterModule, RouterModule,
@@ -107,7 +106,7 @@ export class NewJumpComponent implements OnInit {
private serviceGear: GearService, private serviceGear: GearService,
private dateService: DateService, private dateService: DateService,
private translateService: TranslateService, private translateService: TranslateService,
private statsService: StatsService private statsService: StatsService,
) {} ) {}
ngOnInit() { ngOnInit() {
@@ -126,6 +125,7 @@ export class NewJumpComponent implements OnInit {
} }
onFormSubmit() { onFormSubmit() {
if (this.isValidatedForm()) {
this.pendingAddRequest = true; this.pendingAddRequest = true;
this.serviceJump this.serviceJump
@@ -141,7 +141,7 @@ export class NewJumpComponent implements OnInit {
this.deployAltitude, this.deployAltitude,
this.countOfJumps, this.countOfJumps,
this.comments, this.comments,
this.isSpecial === undefined ? false : this.isSpecial this.isSpecial === undefined ? false : this.isSpecial,
) )
.subscribe(() => { .subscribe(() => {
this.statsService.resetStats(); this.statsService.resetStats();
@@ -155,6 +155,7 @@ export class NewJumpComponent implements OnInit {
this.pendingAddRequest = false; this.pendingAddRequest = false;
}); });
} }
}
public isValidatedForm(): boolean { public isValidatedForm(): boolean {
return ( return (
@@ -200,7 +201,7 @@ export class NewJumpComponent implements OnInit {
data.sort( data.sort(
(a, b) => (a, b) =>
(b.isFavorite ? 1 : 0) - (a.isFavorite ? 1 : 0) || (b.isFavorite ? 1 : 0) - (a.isFavorite ? 1 : 0) ||
a.name.localeCompare(b.name) a.name.localeCompare(b.name),
); );
this.listOfDropZone = data; this.listOfDropZone = data;
this.listOfFilteredDropZone = data; this.listOfFilteredDropZone = data;
@@ -252,7 +253,7 @@ export class NewJumpComponent implements OnInit {
this.listOfFilteredDropZone = this.listOfDropZone; this.listOfFilteredDropZone = this.listOfDropZone;
this.listOfFilteredDropZone = this.listOfFilteredDropZone.filter( this.listOfFilteredDropZone = this.listOfFilteredDropZone.filter(
(option) => option.name.toLowerCase().includes(filterValue) (option) => option.name.toLowerCase().includes(filterValue),
); );
} }
} }

View File

@@ -5,14 +5,13 @@
min-width: 150px; min-width: 150px;
max-width: 500px; max-width: 500px;
width: 100%; width: 100%;
} }
.content { .content {
min-height: 90vh; min-height: 90vh;
display: flex; display: flex;
justify-content: left; justify-content: left;
flex-direction: column; flex-direction: column;
align-items: initial; align-items: initial;
padding-top: 25px; padding-top: 25px;
} }

View File

@@ -11,13 +11,12 @@
</button> </button>
</div> </div>
<form @if (notLoadingToDisplay()) {
class="formNewJumps" <form class="formNewJumps" (ngSubmit)="onFormSubmit()">
(ngSubmit)="onFormSubmit()"
*ngIf="notLoadingToDisplay(); else loading"
>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewTunnelFlight_ChooseJumpType" | translate }}</mat-label> <mat-label>{{
"NewTunnelFlight_ChooseJumpType" | translate
}}</mat-label>
<input <input
type="text" type="text"
matInput matInput
@@ -29,23 +28,27 @@
#autoJumpType="matAutocomplete" #autoJumpType="matAutocomplete"
[displayWith]="displayNameFn" [displayWith]="displayNameFn"
> >
<mat-option *ngFor="let jumpType of listOfJumpType" [value]="jumpType"> @for (jumpType of listOfJumpType; track jumpType) {
<mat-option [value]="jumpType">
{{ jumpType.name }} {{ jumpType.name }}
</mat-option> </mat-option>
}
</mat-autocomplete> </mat-autocomplete>
@if (selectedJumpType) {
<button <button
*ngIf="selectedJumpType"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="selectedJumpType = undefined" (click)="selectedJumpType = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewTunnelFlight_ChooseTunnel" | translate }}</mat-label> <mat-label>{{
"NewTunnelFlight_ChooseTunnel" | translate
}}</mat-label>
<input <input
type="text" type="text"
matInput matInput
@@ -58,26 +61,27 @@
#autoDropZone="matAutocomplete" #autoDropZone="matAutocomplete"
[displayWith]="displayNameFn" [displayWith]="displayNameFn"
> >
<mat-option @for (tunnel of listOfFilteredTunnel; track tunnel) {
*ngFor="let tunnel of listOfFilteredTunnel" <mat-option [value]="tunnel">
[value]="tunnel"
>
{{ tunnel.name }} {{ tunnel.name }}
</mat-option> </mat-option>
}
</mat-autocomplete> </mat-autocomplete>
@if (selectedTunnel) {
<button <button
*ngIf="selectedTunnel"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="resetTunnel()" (click)="resetTunnel()"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewTunnelFlight_Date_Lbl" | translate }}</mat-label> <mat-label>{{
"NewTunnelFlight_Date_Lbl" | translate
}}</mat-label>
<input <input
matInput matInput
[max]="maxDate" [max]="maxDate"
@@ -92,9 +96,10 @@
></mat-datepicker-toggle> ></mat-datepicker-toggle>
<mat-datepicker #flightDateDp disabled="false"></mat-datepicker> <mat-datepicker #flightDateDp disabled="false"></mat-datepicker>
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewTunnelFlight_Minutes_Lbl" | translate }}</mat-label> <mat-label>{{
"NewTunnelFlight_Minutes_Lbl" | translate
}}</mat-label>
<input <input
matInput matInput
placeholder="{{ 'NewTunnelFlight_Minutes' | translate }}" placeholder="{{ 'NewTunnelFlight_Minutes' | translate }}"
@@ -102,19 +107,21 @@
name="minutesOfFlight" name="minutesOfFlight"
type="number" type="number"
/> />
@if (minutesOfFlight) {
<button <button
*ngIf="minutesOfFlight"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="minutesOfFlight = undefined" (click)="minutesOfFlight = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>{{ "NewTunnelFlight_Comments_Lbl" | translate }}</mat-label> <mat-label>{{
"NewTunnelFlight_Comments_Lbl" | translate
}}</mat-label>
<textarea <textarea
matInput matInput
placeholder="{{ 'NewTunnelFlight_Comments' | translate }}" placeholder="{{ 'NewTunnelFlight_Comments' | translate }}"
@@ -122,24 +129,25 @@
name="comments" name="comments"
type="text" type="text"
></textarea> ></textarea>
@if (comments) {
<button <button
*ngIf="comments"
matSuffix matSuffix
mat-icon-button mat-icon-button
aria-label="Clear" aria-label="Clear"
(click)="comments = undefined" (click)="comments = undefined"
> >
<mat-icon>close</mat-icon> <mat-icon svgIcon="close"></mat-icon>
</button> </button>
}
</mat-form-field> </mat-form-field>
<br /> <br />
<button mat-raised-button color="accent" *ngIf="isValidatedForm()"> @if (this.isValidatedForm()) {
<button mat-raised-button color="accent">
{{ "NewTunnelFlight_Submit" | translate }} {{ "NewTunnelFlight_Submit" | translate }}
</button> </button>
}
</form> </form>
} @else {
<ng-template #loading>
<mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner> <mat-progress-spinner [mode]="'indeterminate'"></mat-progress-spinner>
</ng-template> }
</div> </div>

View File

@@ -7,7 +7,7 @@ import {
NativeDateAdapter, NativeDateAdapter,
} from "@angular/material/core"; } from "@angular/material/core";
import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { CommonModule } from "@angular/common";
import { MatIconModule } from "@angular/material/icon"; import { MatIconModule } from "@angular/material/icon";
import { MatOptionModule } from "@angular/material/core"; import { MatOptionModule } from "@angular/material/core";
import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatAutocompleteModule } from "@angular/material/autocomplete";
@@ -52,7 +52,6 @@ class PickDateAdapter extends NativeDateAdapter {
], ],
imports: [ imports: [
TranslateModule, TranslateModule,
CommonModule,
RouterModule, RouterModule,
RouterLink, RouterLink,
FormsModule, FormsModule,
@@ -88,7 +87,7 @@ export class NewTunnelFlightComponent implements OnInit {
private serviceTunnelFlight: TunnelFlightService, private serviceTunnelFlight: TunnelFlightService,
private serviceJumpType: JumpTypeService, private serviceJumpType: JumpTypeService,
private translateService: TranslateService, private translateService: TranslateService,
private dateService: DateService private dateService: DateService,
) {} ) {}
ngOnInit() { ngOnInit() {
@@ -108,6 +107,7 @@ export class NewTunnelFlightComponent implements OnInit {
} }
public onFormSubmit() { public onFormSubmit() {
if (this.isValidatedForm()) {
this.pendingAddRequest = true; this.pendingAddRequest = true;
this.serviceTunnelFlight this.serviceTunnelFlight
@@ -116,7 +116,7 @@ export class NewTunnelFlightComponent implements OnInit {
this.selectedJumpType.id, this.selectedJumpType.id,
this.flightDate, this.flightDate,
this.minutesOfFlight, this.minutesOfFlight,
this.comments this.comments,
) )
.subscribe(() => { .subscribe(() => {
this.comments = undefined; this.comments = undefined;
@@ -127,6 +127,7 @@ export class NewTunnelFlightComponent implements OnInit {
this.pendingAddRequest = false; this.pendingAddRequest = false;
}); });
} }
}
public isValidatedForm(): boolean { public isValidatedForm(): boolean {
return ( return (
@@ -185,8 +186,8 @@ export class NewTunnelFlightComponent implements OnInit {
filterValue = event.toLowerCase(); filterValue = event.toLowerCase();
this.listOfFilteredTunnel = this.listOfTunnel; this.listOfFilteredTunnel = this.listOfTunnel;
this.listOfFilteredTunnel = this.listOfFilteredTunnel.filter((option) => this.listOfFilteredTunnel = this.listOfFilteredTunnel.filter(
option.name.toLowerCase().includes(filterValue) (option) => option.name.toLowerCase().includes(filterValue),
); );
} }
} }

View File

@@ -35,27 +35,48 @@
<ng-template matTabContent> <ng-template matTabContent>
<div class="containerFlex"> <div class="containerFlex">
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ "Summary_LastMonth_ByDz" | translate }}</legend> <legend>
{{ "Summary_LastMonth_ByDz" | translate }}
</legend>
<table mat-table [dataSource]="dsJumpForLastMonthByDz"> <table mat-table [dataSource]="dsJumpForLastMonthByDz">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</fieldset> </fieldset>
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ "Summary_LastMonth_ByJumpType" | translate }}</legend> <legend>
<table mat-table [dataSource]="dsJumpForLastMonthByJumpType"> {{ "Summary_LastMonth_ByJumpType" | translate }}
</legend>
<table
mat-table
[dataSource]="dsJumpForLastMonthByJumpType"
>
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</fieldset> </fieldset>
</div> </div>
@@ -66,27 +87,48 @@
<ng-template matTabContent> <ng-template matTabContent>
<div class="containerFlex"> <div class="containerFlex">
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ "Summary_LastYear_ByDz" | translate }}</legend> <legend>
{{ "Summary_LastYear_ByDz" | translate }}
</legend>
<table mat-table [dataSource]="dsJumpForLastYearByDz"> <table mat-table [dataSource]="dsJumpForLastYearByDz">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</fieldset> </fieldset>
<fieldset class="contentFlex"> <fieldset class="contentFlex">
<legend>{{ "Summary_LastYear_ByJumpType" | translate }}</legend> <legend>
<table mat-table [dataSource]="dsJumpForLastYearByJumpType"> {{ "Summary_LastYear_ByJumpType" | translate }}
</legend>
<table
mat-table
[dataSource]="dsJumpForLastYearByJumpType"
>
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</fieldset> </fieldset>
</div> </div>
@@ -97,12 +139,19 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByDz"> <table mat-table [dataSource]="dsNbJumpByDz">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -111,12 +160,19 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByAircraft"> <table mat-table [dataSource]="dsNbJumpByAircraft">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -125,12 +181,19 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByGear"> <table mat-table [dataSource]="dsNbJumpByGear">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -139,12 +202,19 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByType"> <table mat-table [dataSource]="dsNbJumpByType">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>
@@ -153,12 +223,19 @@
<ng-template matTabContent> <ng-template matTabContent>
<table mat-table [dataSource]="dsNbJumpByYear"> <table mat-table [dataSource]="dsNbJumpByYear">
<ng-container matColumnDef="label"> <ng-container matColumnDef="label">
<td mat-cell *matCellDef="let element">{{ element.label }}</td> <td mat-cell *matCellDef="let element">
{{ element.label }}
</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nb"> <ng-container matColumnDef="nb">
<td mat-cell *matCellDef="let element">{{ element.nb }}</td> <td mat-cell *matCellDef="let element">
{{ element.nb }}
</td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr
mat-row
*matRowDef="let row; columns: displayedColumns"
></tr>
</table> </table>
</ng-template> </ng-template>
</mat-tab> </mat-tab>

View File

@@ -80,9 +80,10 @@ export class SummaryComponent implements OnInit {
const datepipe: DatePipe = new DatePipe("en-US"); const datepipe: DatePipe = new DatePipe("en-US");
let formattedDate = datepipe.transform( let formattedDate = datepipe.transform(
data.lastJump.jumpDate, data.lastJump.jumpDate,
"EEEE dd MMMM YYYY", "EEEE dd MMMM yyyy",
); );
this.lastJump = formattedDate + " (" + data.lastJump.dropZone.name + ")"; this.lastJump =
formattedDate + " (" + data.lastJump.dropZone.name + ")";
}); });
this.serviceApi.getStatsOfLastMonth().subscribe((data) => { this.serviceApi.getStatsOfLastMonth().subscribe((data) => {
@@ -193,7 +194,9 @@ export class SummaryComponent implements OnInit {
const now = new Date(); const now = new Date();
const currentYear = now.getFullYear(); const currentYear = now.getFullYear();
const nbYears = currentYear - firstYear; const nbYears = currentYear - firstYear;
let listOfYears = new Array(nbYears).fill(null).map(() => firstYear++); let listOfYears = new Array(nbYears)
.fill(null)
.map(() => firstYear++);
// Prepare the list of jump type with am empty array // Prepare the list of jump type with am empty array
let tmpResults = new Map<string, number[]>(); let tmpResults = new Map<string, number[]>();

View File

@@ -4,44 +4,61 @@
<form [formGroup]="userForm" (ngSubmit)="onSubmit(userForm.value)"> <form [formGroup]="userForm" (ngSubmit)="onSubmit(userForm.value)">
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Login</mat-label> <mat-label>{{ "UserProfile_Login" | translate }}</mat-label>
<input matInput type="text" formControlName="login" readonly /> <input
matInput
type="text"
formControlName="login"
readonly
/>
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Firstname</mat-label> <mat-label>{{
"UserProfile_Firstname" | translate
}}</mat-label>
<input matInput type="text" formControlName="firstName" /> <input matInput type="text" formControlName="firstName" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Lastname</mat-label> <mat-label>{{
"UserProfile_Lastname" | translate
}}</mat-label>
<input matInput type="text" formControlName="lastName" /> <input matInput type="text" formControlName="lastName" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>E-mail</mat-label> <mat-label>{{ "UserProfile_Mail" | translate }}</mat-label>
<input matInput type="text" formControlName="email" /> <input matInput type="text" formControlName="email" />
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>Current password</mat-label> <mat-label>{{
<input matInput type="text" formControlName="currentPassword" /> "UserProfile_CurrentPassword" | translate
}}</mat-label>
<input
matInput
type="text"
formControlName="currentPassword"
/>
</mat-form-field> </mat-form-field>
</p> </p>
<p> <p>
<mat-form-field> <mat-form-field>
<mat-label>New password</mat-label> <mat-label>{{
"UserProfile_NewPassword" | translate
}}</mat-label>
<input matInput type="text" formControlName="newPassword" /> <input matInput type="text" formControlName="newPassword" />
</mat-form-field> </mat-form-field>
</p> </p>
<button type="submit" mat-raised-button color="accent"> <button type="submit" mat-raised-button color="accent">
Update my profile {{ "UserProfile_Update" | translate }}
</button> </button>
</form> </form>
</fieldset> </fieldset>

View File

@@ -30,6 +30,7 @@ import { ServiceComm } from "../../services/service-comm.service";
MatInputModule, MatInputModule,
MatButtonModule, MatButtonModule,
TranslateModule, TranslateModule,
TranslatePipe,
], ],
}) })
export class UserProfileComponent implements OnInit { export class UserProfileComponent implements OnInit {

View File

@@ -11,22 +11,22 @@
"LoginUser_UsernamePattern": "Username must have min 3 characters", "LoginUser_UsernamePattern": "Username must have min 3 characters",
"LoginUser_UsernameRequired": "Username is required", "LoginUser_UsernameRequired": "Username is required",
"LoginCreateUser_Firstname": "Firstname", "CreateUser_Firstname": "Firstname",
"LoginCreateUser_FirstnameRequired": "Firstname is required", "CreateUser_FirstnameRequired": "Firstname is required",
"LoginCreateUser_FirstnamePattern": "Firstname must have min 3 characters", "CreateUser_FirstnamePattern": "Firstname must have min 3 characters",
"LoginCreateUser_Lastname": "Lastname", "CreateUser_Lastname": "Lastname",
"LoginCreateUser_LastnameRequired": "Lastname is required", "CreateUser_LastnameRequired": "Lastname is required",
"LoginCreateUser_LastnamePattern": "Lastname must have min 3 characters", "CreateUser_LastnamePattern": "Lastname must have min 3 characters",
"LoginCreateUser_Email": "E-mail", "CreateUser_Email": "E-mail",
"LoginCreateUser_EmailRequired": "E-mail is required", "CreateUser_EmailRequired": "E-mail is required",
"LoginCreateUser_EmailPattern": "It's not a e-mail", "CreateUser_EmailPattern": "It's not a e-mail",
"LoginCreateUser_Username": "Username", "CreateUser_Username": "Username",
"LoginCreateUser_UsernameRequired": "Username is required", "CreateUser_UsernameRequired": "Username is required",
"LoginCreateUser_UsernamePattern": "Username must have min 3 characters", "CreateUser_UsernamePattern": "Username must have min 3 characters",
"LoginCreateUser_Password": "Password", "CreateUser_Password": "Password",
"LoginCreateUser_PasswordRequired": "Password is required", "CreateUser_PasswordRequired": "Password is required",
"LoginCreateUser_PasswordPattern": "The pattern of the password ([A-Za-z0-9_-|/]{{ '{' }}8,15{{ '}' }})", "CreateUser_PasswordPattern": "The pattern of the password ([A-Za-z0-9_-|/]{{ '{' }}8,15{{ '}' }})",
"LoginCreateUser_BtnLogin": "Create user and login", "CreateUser_BtnLogin": "Create user and login",
"Default_Title": "Home", "Default_Title": "Home",
"ListDz_Title": "List of DZs", "ListDz_Title": "List of DZs",
@@ -135,5 +135,13 @@
"ListTunnelFlight_12Months": "On 12 last months", "ListTunnelFlight_12Months": "On 12 last months",
"ListTunnelFlight_Add": "Add tunnel flights", "ListTunnelFlight_Add": "Add tunnel flights",
"ListTunnelFlight_LoadTable": "Load the tunnel flights", "ListTunnelFlight_LoadTable": "Load the tunnel flights",
"ListTunnelFlight_AllFlights": "All" "ListTunnelFlight_AllFlights": "All",
"UserProfile_Update": "Update my profile",
"UserProfile_NewPassword": "New password",
"UserProfile_CurrentPassword": "Current password",
"UserProfile_Mail": "E-mail",
"UserProfile_Lastname": "Lastname",
"UserProfile_Firstname": "Firstname",
"UserProfile_Login": "Login"
} }

View File

@@ -11,22 +11,22 @@
"LoginUser_UsernamePattern": "L'identifiant doit être minimum de 3 caractères", "LoginUser_UsernamePattern": "L'identifiant doit être minimum de 3 caractères",
"LoginUser_UsernameRequired": "L'identifiant est obligatoire", "LoginUser_UsernameRequired": "L'identifiant est obligatoire",
"LoginCreateUser_Firstname": "Prénom", "CreateUser_Firstname": "Prénom",
"LoginCreateUser_FirstnameRequired": "Le prénom est obligatoire", "CreateUser_FirstnameRequired": "Le prénom est obligatoire",
"LoginCreateUser_FirstnamePattern": "Le prénom doit être minimum de 3 caractères", "CreateUser_FirstnamePattern": "Le prénom doit être minimum de 3 caractères",
"LoginCreateUser_Lastname": "Nom", "CreateUser_Lastname": "Nom",
"LoginCreateUser_LastnameRequired": "Le nom est obligatoire", "CreateUser_LastnameRequired": "Le nom est obligatoire",
"LoginCreateUser_LastnamePattern": "Le nom doit être minimum de 3 caractères", "CreateUser_LastnamePattern": "Le nom doit être minimum de 3 caractères",
"LoginCreateUser_Email": "E-mail", "CreateUser_Email": "E-mail",
"LoginCreateUser_EmailRequired": "E-mail est obligatoire", "CreateUser_EmailRequired": "E-mail est obligatoire",
"LoginCreateUser_EmailPattern": "Ceci n'est pas un adresse mail", "CreateUser_EmailPattern": "Ceci n'est pas un adresse mail",
"LoginCreateUser_Username": "Identifiant", "CreateUser_Username": "Identifiant",
"LoginCreateUser_UsernameRequired": "L'identifiant est obligatoire", "CreateUser_UsernameRequired": "L'identifiant est obligatoire",
"LoginCreateUser_UsernamePattern": "L'identifiant doit être minimum de 3 caractères", "CreateUser_UsernamePattern": "L'identifiant doit être minimum de 3 caractères",
"LoginCreateUser_Password": "Mot de passe", "CreateUser_Password": "Mot de passe",
"LoginCreateUser_PasswordRequired": "Le mot de passe est obligatoire", "CreateUser_PasswordRequired": "Le mot de passe est obligatoire",
"LoginCreateUser_PasswordPattern": "Le mot de passe doit contenir lettres minuscule/majuscule et entre 8 et 15 caractères.", "CreateUser_PasswordPattern": "Le mot de passe doit contenir lettres minuscule/majuscule et entre 8 et 15 caractères.",
"LoginCreateUser_BtnLogin": "Créer et se connecter", "CreateUser_BtnLogin": "Créer et se connecter",
"Default_Title": "Accueil", "Default_Title": "Accueil",
"ListDz_Title": "Liste des centres de parachutisme", "ListDz_Title": "Liste des centres de parachutisme",
@@ -135,5 +135,13 @@
"ListTunnelFlight_12Months": "Sur 12 derniers mois", "ListTunnelFlight_12Months": "Sur 12 derniers mois",
"ListTunnelFlight_Add": "Ajouter du temps en soufflerie", "ListTunnelFlight_Add": "Ajouter du temps en soufflerie",
"ListTunnelFlight_LoadTable": "Charger les vols en tunnel", "ListTunnelFlight_LoadTable": "Charger les vols en tunnel",
"ListTunnelFlight_AllFlights": "Tous les vols" "ListTunnelFlight_AllFlights": "Tous les vols",
"UserProfile_Update": "Mise à jour",
"UserProfile_NewPassword": "Nouveau mot de passe",
"UserProfile_CurrentPassword": "Actuel mot de passe",
"UserProfile_Mail": "E-mail",
"UserProfile_Lastname": "Nom",
"UserProfile_Firstname": "Prénom",
"UserProfile_Login": "Identifiant"
} }

12
doc.txt
View File

@@ -1,7 +1,11 @@
To build an image "toto" with the version "0.1": podman build . -t skydivelogs:1.5.0 To build an image "skydivelogs" with the version "1.5.5":
podman build . -t skydivelogs:1.5.5
To run ab image to container with volume : To run ab image to container with volume :
podman run -v C:\toto\config:/app/Front/config -v C:\toto\db:/app/API/Data -d -p 5080:80/tcp --name Test -it skydivelogs:1.5.0 podman run -v ./Front/skydivelogs-app/src/config:/usr/share/nginx/html/config:z -v ./Back/skydiveLogs-api/Data:/app/Data:z -d -p 5080:80/tcp --name Skydivelogs-1.5.5 -it skydivelogs:1.5.5
podman save --output skydivelogs-1.5.0.tar skydivelogs:1.5.0 To save the image before to updload to the server :
podman save --output skydivelogs-1.5.5.tar skydivelogs:1.5.5
scp -P 5022 skydivelogs-1.5.0.tar administrator@51.75.68.58:~ Updload to the server :
scp -P 5022 skydivelogs-1.5.5.tar administrator@51.75.68.58:~

View File

@@ -1,6 +0,0 @@
#!/bin/sh
service nginx start
cd /app/API/
dotnet skydiveLogs-api.dll