Skip to content

Commit c87f377

Browse files
Adopts standalone components in frontend and improves maintainability
1 parent ff169f7 commit c87f377

File tree

72 files changed

+1422
-1320
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1422
-1320
lines changed

frontend/package-lock.json

+142-201
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

+11-11
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
},
1111
"private": true,
1212
"dependencies": {
13-
"@angular/animations": "^19.0.4",
14-
"@angular/common": "^19.0.4",
15-
"@angular/compiler": "^19.0.4",
16-
"@angular/core": "^19.0.4",
17-
"@angular/forms": "^19.0.4",
18-
"@angular/platform-browser": "^19.0.4",
19-
"@angular/platform-browser-dynamic": "^19.0.4",
20-
"@angular/router": "^19.0.4",
13+
"@angular/animations": "^19.0.5",
14+
"@angular/common": "^19.0.5",
15+
"@angular/compiler": "^19.0.5",
16+
"@angular/core": "^19.0.5",
17+
"@angular/forms": "^19.0.5",
18+
"@angular/platform-browser": "^19.0.5",
19+
"@angular/platform-browser-dynamic": "^19.0.5",
20+
"@angular/router": "^19.0.5",
2121
"@fortawesome/fontawesome-free": "^6.4.2",
2222
"@ng-select/ng-select": "~14.1.0",
2323
"@types/bootstrap": "^5.2.7",
@@ -32,9 +32,9 @@
3232
"zone.js": "^0.15.0"
3333
},
3434
"devDependencies": {
35-
"@angular-devkit/build-angular": "^19.0.5",
36-
"@angular/cli": "~19.0.5",
37-
"@angular/compiler-cli": "^19.0.4",
35+
"@angular-devkit/build-angular": "^19.0.6",
36+
"@angular/cli": "~19.0.6",
37+
"@angular/compiler-cli": "^19.0.5",
3838
"@types/jasmine": "~5.1.0",
3939
"jasmine-core": "~5.1.1",
4040
"karma": "~6.4.2",

frontend/src/app/app.component.html

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
<header *ngIf="this.showHeader">
2-
<app-layout-header></app-layout-header>
3-
</header>
1+
@if (this.showHeader) {
2+
<header>
3+
<app-layout-header></app-layout-header>
4+
</header>
5+
}
46
<main class="container-fluid">
57
<div class="row">
6-
<aside class="col-3 p-1" *ngIf="this.showAside">
7-
<app-layout-aside></app-layout-aside>
8-
</aside>
8+
@if (this.showAside) {
9+
<aside class="col-3 p-1">
10+
<app-layout-aside></app-layout-aside>
11+
</aside>
12+
}
13+
914
<section [ngClass]='{"col-9": this.showAside, "col-12": !this.showAside}'>
1015
<app-not-supported-file-system-access-api></app-not-supported-file-system-access-api>
1116
<router-outlet></router-outlet>

frontend/src/app/app.component.spec.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import { TestBed } from '@angular/core/testing';
2-
import { RouterTestingModule } from '@angular/router/testing';
32
import { AppComponent } from './app.component';
43

54
describe('AppComponent', () => {
65
beforeEach(async () => {
76
await TestBed.configureTestingModule({
8-
imports: [
9-
RouterTestingModule
10-
],
11-
declarations: [
12-
AppComponent
13-
],
7+
imports: [AppComponent]
148
}).compileComponents();
159
});
1610

frontend/src/app/app.component.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
1+
import { CommonModule } from "@angular/common";
12
import { Component } from '@angular/core';
2-
import { ActivatedRoute, Data, Event, NavigationEnd, ResolveEnd, Router } from "@angular/router";
3+
import { Data, Event, NavigationEnd, ResolveEnd, Router, RouterOutlet } from "@angular/router";
34
import { Observable } from 'rxjs';
5+
import { NotSupportedFileSystemAccessApiComponent } from "./components/helpers/not-supported-file-system-access-api/not-supported-file-system-access-api.component";
6+
import { AsideComponent } from "./components/layout/aside/aside.component";
7+
import { HeaderComponent } from "./components/layout/header/header.component";
48

59
@Component({
610
selector: 'app-root',
711
templateUrl: './app.component.html',
8-
styleUrls: ['./app.component.scss'],
9-
standalone: false
12+
imports: [
13+
AsideComponent,
14+
HeaderComponent,
15+
NotSupportedFileSystemAccessApiComponent,
16+
17+
CommonModule,
18+
RouterOutlet
19+
],
20+
styleUrls: ['./app.component.scss']
1021
})
1122
export class AppComponent {
1223
title = 'VSCode4Teaching';
@@ -17,7 +28,7 @@ export class AppComponent {
1728
nextShowAside: boolean | undefined = undefined;
1829
nextShowHeader: boolean | undefined = undefined;
1930

20-
constructor(private router: Router, private activatedRoute: ActivatedRoute) {
31+
constructor(private router: Router) {
2132
(<Observable<Event>>this.router.events).subscribe((routerEvent: Event) => {
2233
if (routerEvent instanceof ResolveEnd) {
2334
const deepestChild = ((e) => {

frontend/src/app/app.config.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from "@angular/common/http";
2+
import { ApplicationConfig } from "@angular/core";
3+
import { provideRouter, RouterModule } from "@angular/router";
4+
import { AuthPersistenceMethodInterface } from "@app-services/auth/persistence-methods/auth-persistence-method-interface.service";
5+
import { AuthSessionstorage } from "@app-services/auth/persistence-methods/auth-sessionstorage.class";
6+
import { HttpRequestInterceptor } from "@app-services/rest-api/interceptor/http-request.interceptor";
7+
import { UrlService } from "@app-services/url/url.service";
8+
import { WebSocketHandler } from "@app-services/ws/web-socket-handler";
9+
import { WebSocketHandlerFactory } from "@app-services/ws/web-socket-handler-factory.service";
10+
import { routes } from "./app.routes";
11+
12+
export const appConfig: ApplicationConfig = {
13+
providers: [
14+
provideRouter(routes),
15+
{ provide: RouterModule, useValue: RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' }) },
16+
17+
provideHttpClient(withInterceptorsFromDi()),
18+
19+
{ provide: AuthPersistenceMethodInterface, useClass: AuthSessionstorage },
20+
21+
{ provide: HTTP_INTERCEPTORS, useClass: HttpRequestInterceptor, multi: true },
22+
{ provide: Window, useValue: window },
23+
24+
{ provide: WebSocketHandler, useFactory: WebSocketHandlerFactory, deps: [UrlService, AuthPersistenceMethodInterface] },
25+
]
26+
}

frontend/src/app/app.module.ts

-104
This file was deleted.

frontend/src/app/app-routing.module.ts renamed to frontend/src/app/app.routes.ts

+2-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { NgModule } from '@angular/core';
2-
import { RouterModule, Routes } from '@angular/router';
1+
import { Routes } from '@angular/router';
32
import { DashboardComponent } from "./components/private/common/dashboard/dashboard.component";
43
import { StudentCourseComponent } from "./components/private/student/course/student-course.component";
54
import { TeacherCourseComponent } from "./components/private/teacher/course/teacher-course.component";
@@ -8,7 +7,7 @@ import { IndexComponent } from "./components/public/index/index.component";
87
import { LoginComponent } from "./components/public/login/login.component";
98
import { isLoggedIn, isTeacher } from "./services/auth/guards/guards.service";
109

11-
const routes: Routes = [
10+
export const routes: Routes = [
1211
// private/common
1312
{ path: "dashboard", component: DashboardComponent, data: { showAside: false }, canActivate: [isLoggedIn] },
1413

@@ -33,12 +32,3 @@ const routes: Routes = [
3332
{ path: "login", component: LoginComponent, data: { showAside: false, showHeader: false } },
3433
{ path: "", component: IndexComponent, data: { showAside: false } }
3534
];
36-
37-
@NgModule({
38-
imports: [RouterModule.forRoot(routes, {
39-
onSameUrlNavigation: 'reload'
40-
})],
41-
exports: [RouterModule]
42-
})
43-
export class AppRoutingModule {
44-
}

frontend/src/app/components/helpers/delay-since/delay-since.component.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@
22

33
@Component({
44
selector: 'app-helper-delay-since',
5-
templateUrl: './delay-since.component.html',
6-
standalone: false
5+
templateUrl: './delay-since.component.html'
76
})
87
export class DelaySinceComponent implements OnInit, OnChanges, OnDestroy {
98
@Input("since") since!: Date;
@@ -31,7 +30,7 @@ export class DelaySinceComponent implements OnInit, OnChanges, OnDestroy {
3130
ngOnDestroy() {
3231
// Clear the interval when the component is destroyed
3332
if (this.elapsedTimeIntervalId) {
34-
clearInterval(this.elapsedTimeIntervalId);
33+
window.clearInterval(this.elapsedTimeIntervalId);
3534
}
3635
}
3736

@@ -69,9 +68,9 @@ export class DelaySinceComponent implements OnInit, OnChanges, OnDestroy {
6968
this.readableElapsedTime = `${Math.floor(elapsedTime)} ${unit}`;
7069

7170
if (this.elapsedTimeIntervalId !== undefined) {
72-
clearInterval(this.elapsedTimeIntervalId);
71+
window.clearInterval(this.elapsedTimeIntervalId);
7372
}
74-
this.elapsedTimeIntervalId = setInterval(() => {
73+
this.elapsedTimeIntervalId = window.setInterval(() => {
7574
this.getInterpretedElapsedTime();
7675
}, nextDelay);
7776
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
<div class="container justify-content-center" *ngIf="this.showFsaAPINotSupportedMessage">
2-
<div class="row">
3-
<div class="col mt-1 mb-3">
4-
<div class="alert alert-v4t text-center">
5-
<i class="fa fa-exclamation-circle"></i>&nbsp;<strong>Attention!</strong> This web browser does not support interaction with your computer files and folders, so you will not be able to use features like exercise download or automatic file synchronization.
6-
<br>If you want to use these features, please use a compatible browser like most recent versions of Google Chrome or Microsoft Edge. Check out compatibility in <a href="https://caniuse.com/native-filesystem-api" target="_blank" class="link-v4t link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover">this link</a>.
1+
@if (this.showFsaAPINotSupportedMessage) {
2+
<div class="container justify-content-center">
3+
<div class="row">
4+
<div class="col mt-1 mb-3">
5+
<div class="alert alert-v4t text-center">
6+
<i class="fa fa-exclamation-circle"></i>&nbsp;<strong>Attention!</strong> This web browser does not support interaction with your computer files and folders, so you will not be able to use features like exercise download or automatic file synchronization.
7+
<br>If you want to use these features, please use a compatible browser like most recent versions of Google Chrome or Microsoft Edge. Check out compatibility in <a href="https://caniuse.com/native-filesystem-api" target="_blank" class="link-v4t link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover">this link</a>.
8+
</div>
79
</div>
810
</div>
911
</div>
10-
</div>
12+
}

frontend/src/app/components/helpers/not-supported-file-system-access-api/not-supported-file-system-access-api.component.scss

Whitespace-only changes.

frontend/src/app/components/helpers/not-supported-file-system-access-api/not-supported-file-system-access-api.component.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { Component, OnDestroy, OnInit } from '@angular/core';
22
import { Event, NavigationStart, Router } from "@angular/router";
3+
import { CurrentUserService } from "@app-services/auth/current-user/current-user.service";
34
import { supported as fileSystemAccessApiSupported } from "browser-fs-access";
45
import { Subscription } from "rxjs";
5-
import { CurrentUserService } from "../../../services/auth/current-user/current-user.service";
66

77
@Component({
88
selector: 'app-not-supported-file-system-access-api',
9-
templateUrl: './not-supported-file-system-access-api.component.html',
10-
styleUrls: ['./not-supported-file-system-access-api.component.scss'],
11-
standalone: false
9+
templateUrl: './not-supported-file-system-access-api.component.html'
1210
})
1311
export class NotSupportedFileSystemAccessApiComponent implements OnInit, OnDestroy {
1412
public showFsaAPINotSupportedMessage: boolean;
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
<div *ngIf="info.visible" class="progress" role="progressbar" aria-label="Basic example" [attr.aria-valuenow]="info.percentage" aria-valuemin="0" aria-valuemax="100" style="width: 100%; background-color: rgba(244, 74, 62, .2)">
2-
<div [ngClass]="{ 'progress-bar-striped': info.percentage < 100 }" class="progress-bar progress-bar-animated overflow-visible" [ngStyle]="{ 'width': info.percentage + '%', 'background-color': '#F44A3E', 'color': '#333333' }">{{ info.process }} ({{ Math.round(info.percentage) }}%)</div>
3-
</div>
1+
@if (info.visible) {
2+
<div class="progress" role="progressbar" aria-label="Basic example" [attr.aria-valuenow]="info.percentage" aria-valuemin="0" aria-valuemax="100" style="width: 100%; background-color: rgba(244, 74, 62, .2)">
3+
<div [ngClass]="{ 'progress-bar-striped': info.percentage < 100 }" class="progress-bar progress-bar-animated overflow-visible" [ngStyle]="{ 'width': info.percentage + '%', 'background-color': '#F44A3E', 'color': '#333333' }">{{ info.process }} ({{ Math.round(info.percentage) }}%)</div>
4+
</div>
5+
}

frontend/src/app/components/helpers/progress-bar/progress-bar.component.scss

Whitespace-only changes.

frontend/src/app/components/helpers/progress-bar/progress-bar.component.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { CommonModule } from "@angular/common";
12
import { Component, Input } from '@angular/core';
23

34
export interface ProgressBarDTO {
@@ -8,9 +9,10 @@ export interface ProgressBarDTO {
89

910
@Component({
1011
selector: 'app-helper-progress-bar',
11-
templateUrl: './progress-bar.component.html',
12-
styleUrls: ['./progress-bar.component.scss'],
13-
standalone: false
12+
imports: [
13+
CommonModule
14+
],
15+
templateUrl: './progress-bar.component.html'
1416
})
1517
export class ProgressBarComponent {
1618
@Input("info") public info!: ProgressBarDTO;

0 commit comments

Comments
 (0)