autocomit

This commit is contained in:
2026-02-07 17:51:17 +01:00
parent ff2eb62174
commit b752e26526
68 changed files with 8291 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
+76
View File
@@ -0,0 +1,76 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"ldpv2-frontend": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/ldpv2-frontend",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "ldpv2-frontend:build:production"
},
"development": {
"buildTarget": "ldpv2-frontend:build:development"
}
},
"defaultConfiguration": "development",
"options": {
"proxyConfig": "proxy.conf.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json",
"assets": ["src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
}
}
}
}
}
}
+291
View File
@@ -0,0 +1,291 @@
#!/bin/bash
BASE="/home/claude/ldpv2-monorepo/frontend/src/app"
# ========== MODELS ==========
cat > "$BASE/shared/models/user.model.ts" << 'TS'
export interface User {
id: string;
username: string;
email: string;
role: string;
createdAt: Date;
updatedAt: Date;
}
export interface LoginRequest {
username: string;
password: string;
}
export interface RegisterRequest {
username: string;
email: string;
password: string;
}
export interface AuthResponse {
token: string;
type: string;
user: User;
}
TS
cat > "$BASE/shared/models/environment.model.ts" << 'TS'
export interface Environment {
id: string;
name: string;
description?: string;
isProduction: boolean;
criticalityLevel?: number;
createdAt: Date;
updatedAt: Date;
}
export interface CreateEnvironmentRequest {
name: string;
description?: string;
isProduction?: boolean;
criticalityLevel?: number;
}
export interface UpdateEnvironmentRequest {
name?: string;
description?: string;
isProduction?: boolean;
criticalityLevel?: number;
}
export interface Page<T> {
content: T[];
pageable: {
pageNumber: number;
pageSize: number;
sort: {
sorted: boolean;
unsorted: boolean;
};
};
totalElements: number;
totalPages: number;
last: boolean;
first: boolean;
size: number;
number: number;
numberOfElements: number;
empty: boolean;
}
TS
echo "Models created"
# ========== SERVICES ==========
cat > "$BASE/core/auth/auth.service.ts" << 'TS'
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject, tap } from 'rxjs';
import { LoginRequest, RegisterRequest, AuthResponse, User } from '../../shared/models/user.model';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private readonly TOKEN_KEY = 'auth_token';
private readonly USER_KEY = 'current_user';
private currentUserSubject = new BehaviorSubject<User | null>(this.getUserFromStorage());
public currentUser$ = this.currentUserSubject.asObservable();
constructor(
private http: HttpClient,
private router: Router
) {}
login(credentials: LoginRequest): Observable<AuthResponse> {
return this.http.post<AuthResponse>('/api/auth/login', credentials).pipe(
tap(response => {
this.setSession(response);
})
);
}
register(data: RegisterRequest): Observable<AuthResponse> {
return this.http.post<AuthResponse>('/api/auth/register', data).pipe(
tap(response => {
this.setSession(response);
})
);
}
logout(): void {
localStorage.removeItem(this.TOKEN_KEY);
localStorage.removeItem(this.USER_KEY);
this.currentUserSubject.next(null);
this.router.navigate(['/login']);
}
isAuthenticated(): boolean {
return !!this.getToken();
}
getToken(): string | null {
return localStorage.getItem(this.TOKEN_KEY);
}
getCurrentUser(): User | null {
return this.currentUserSubject.value;
}
private setSession(authResponse: AuthResponse): void {
localStorage.setItem(this.TOKEN_KEY, authResponse.token);
localStorage.setItem(this.USER_KEY, JSON.stringify(authResponse.user));
this.currentUserSubject.next(authResponse.user);
}
private getUserFromStorage(): User | null {
const userJson = localStorage.getItem(this.USER_KEY);
return userJson ? JSON.parse(userJson) : null;
}
}
TS
cat > "$BASE/features/environments/environment.service.ts" << 'TS'
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import {
Environment,
CreateEnvironmentRequest,
UpdateEnvironmentRequest,
Page
} from '../../shared/models/environment.model';
@Injectable({
providedIn: 'root'
})
export class EnvironmentService {
private readonly API_URL = '/api/environments';
constructor(private http: HttpClient) {}
getEnvironments(
page: number = 0,
size: number = 20,
sortBy: string = 'name',
sortDirection: string = 'asc'
): Observable<Page<Environment>> {
const params = new HttpParams()
.set('page', page.toString())
.set('size', size.toString())
.set('sortBy', sortBy)
.set('sortDirection', sortDirection);
return this.http.get<Page<Environment>>(this.API_URL, { params });
}
searchEnvironments(query: string, page: number = 0, size: number = 20): Observable<Page<Environment>> {
const params = new HttpParams()
.set('query', query)
.set('page', page.toString())
.set('size', size.toString());
return this.http.get<Page<Environment>>(`${this.API_URL}/search`, { params });
}
getEnvironment(id: string): Observable<Environment> {
return this.http.get<Environment>(`${this.API_URL}/${id}`);
}
createEnvironment(data: CreateEnvironmentRequest): Observable<Environment> {
return this.http.post<Environment>(this.API_URL, data);
}
updateEnvironment(id: string, data: UpdateEnvironmentRequest): Observable<Environment> {
return this.http.put<Environment>(`${this.API_URL}/${id}`, data);
}
deleteEnvironment(id: string): Observable<void> {
return this.http.delete<void>(`${this.API_URL}/${id}`);
}
}
TS
echo "Services created"
# ========== INTERCEPTORS ==========
cat > "$BASE/core/interceptors/jwt.interceptor.ts" << 'TS'
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../auth/auth.service';
export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
const token = authService.getToken();
if (token && !req.url.includes('/auth/')) {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next(req);
};
TS
cat > "$BASE/core/interceptors/error.interceptor.ts" << 'TS'
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, throwError } from 'rxjs';
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
const router = inject(Router);
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
// Unauthorized - redirect to login
localStorage.removeItem('auth_token');
localStorage.removeItem('current_user');
router.navigate(['/login']);
}
return throwError(() => error);
})
);
};
TS
echo "Interceptors created"
# ========== GUARDS ==========
cat > "$BASE/core/guards/auth.guard.ts" << 'TS'
import { inject } from '@angular/core';
import { Router, CanActivateFn } from '@angular/router';
import { AuthService } from '../auth/auth.service';
export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isAuthenticated()) {
return true;
}
// Store the attempted URL for redirecting
router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
};
TS
echo "Guards created"
echo "✓ All Angular TypeScript files created successfully!"
+40
View File
@@ -0,0 +1,40 @@
{
"name": "ldpv2-frontend",
"version": "1.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"lint": "ng lint"
},
"private": true,
"dependencies": {
"@angular/animations": "^18.0.0",
"@angular/common": "^18.0.0",
"@angular/compiler": "^18.0.0",
"@angular/core": "^18.0.0",
"@angular/forms": "^18.0.0",
"@angular/material": "^18.0.0",
"@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.0.0",
"@angular/cli": "^18.0.0",
"@angular/compiler-cli": "^18.0.0",
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.4.0"
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"/api": {
"target": "http://localhost:8080",
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
template: '<router-outlet></router-outlet>',
styles: []
})
export class AppComponent {
title = 'LDPv2 - Lifecycle Data Platform';
}
+18
View File
@@ -0,0 +1,18 @@
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideAnimations } from '@angular/platform-browser/animations';
import { routes } from './app.routes';
import { jwtInterceptor } from './core/interceptors/jwt.interceptor';
import { errorInterceptor } from './core/interceptors/error.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideHttpClient(
withInterceptors([jwtInterceptor, errorInterceptor])
),
provideAnimations()
]
};
+40
View File
@@ -0,0 +1,40 @@
import { Routes } from '@angular/router';
import { authGuard } from './core/guards/auth.guard';
export const routes: Routes = [
{
path: '',
redirectTo: '/environments',
pathMatch: 'full'
},
{
path: 'login',
loadComponent: () => import('./core/auth/login/login.component').then(m => m.LoginComponent)
},
{
path: 'environments',
canActivate: [authGuard],
children: [
{
path: '',
loadComponent: () => import('./features/environments/environment-list/environment-list.component')
.then(m => m.EnvironmentListComponent)
},
{
path: 'new',
loadComponent: () => import('./features/environments/environment-form/environment-form.component')
.then(m => m.EnvironmentFormComponent)
},
{
path: ':id',
loadComponent: () => import('./features/environments/environment-detail/environment-detail.component')
.then(m => m.EnvironmentDetailComponent)
},
{
path: ':id/edit',
loadComponent: () => import('./features/environments/environment-form/environment-form.component')
.then(m => m.EnvironmentFormComponent)
}
]
}
];
@@ -0,0 +1,25 @@
export interface User {
id: string;
username: string;
email: string;
role: string;
createdAt: Date;
updatedAt: Date;
}
export interface LoginRequest {
username: string;
password: string;
}
export interface RegisterRequest {
username: string;
email: string;
password: string;
}
export interface AuthResponse {
token: string;
type: string;
user: User;
}
+15
View File
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>LDPv2 - Lifecycle Data Platform</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<app-root></app-root>
</body>
</html>
+6
View File
@@ -0,0 +1,6 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));
+39
View File
@@ -0,0 +1,39 @@
/* Global Styles */
@import '@angular/material/prebuilt-themes/indigo-pink.css';
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Roboto, "Helvetica Neue", sans-serif;
height: 100vh;
margin: 0;
}
html, body {
height: 100%;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.mat-mdc-card {
margin-bottom: 20px;
}
.error-message {
color: #f44336;
font-size: 12px;
margin-top: 4px;
}
.success-message {
color: #4caf50;
font-size: 14px;
}
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}
+28
View File
@@ -0,0 +1,28 @@
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": ["jasmine"]
},
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}