Skip to content

Commit d5b8c6d

Browse files
committed
Merge branch 'main' of github.com:geo-engine/geoengine-ui into geoengine-2-rework
2 parents 7984b09 + fd77b15 commit d5b8c6d

16 files changed

+513
-31
lines changed

projects/manager/src/app/app-routing.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {RouterModule, Routes} from '@angular/router';
33
import {NavigationComponent} from './navigation/navigation.component';
44
import {LogInGuard} from './util/guards/log-in.guard';
55
import {BackendAvailableGuard, CanRegisterGuard, LoginComponent, RegisterComponent} from '@geoengine/common';
6+
import {OidcPopupComponent} from './oidc-popup/oidc-popup.component';
67

78
const routes: Routes = [
89
{path: '', redirectTo: 'navigation', pathMatch: 'full'},
@@ -14,6 +15,10 @@ const routes: Routes = [
1415
data: {loginRedirect: '/navigation'},
1516
canActivate: [BackendAvailableGuard, CanRegisterGuard],
1617
},
18+
{
19+
path: 'oidc-popup',
20+
component: OidcPopupComponent,
21+
},
1722
];
1823

1924
@NgModule({
@@ -23,6 +28,7 @@ const routes: Routes = [
2328
initialNavigation: 'disabled', // navigation is enabled in app component after removing query params before the hash
2429
onSameUrlNavigation: 'reload', // for reload the page and checking if the user is logged in again
2530
bindToComponentInputs: true,
31+
// enableTracing: true, // TODO: remove after debugging
2632
}),
2733
],
2834
exports: [RouterModule],

projects/manager/src/app/app.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ export class AppComponent implements OnInit {
2323
await firstValueFrom(this.userService.getSessionOrUndefinedStream());
2424

2525
if (window.location.search.length > 0) {
26+
const hashLocation = window.location.hash.slice(1); // remove the leading '#'
27+
2628
// remove the query parameters before the hash from the url because they are not part of the app and cannot be removed later on
2729
// services can get the original query parameters from the `URLSearchParams` in their constructor which is called before the routing is initialized.
2830
const search = window.location.search;
2931
window.history.replaceState(null, '', window.location.pathname);
30-
this.location.go('/', search);
32+
this.location.go(hashLocation, search);
3133
}
3234

3335
this.router.initialNavigation();
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@if (isError()) {
2+
<div class="error">An error occurred during authentication.</div>
3+
} @else {
4+
<div class="info">You have been redirected here after authentication. You can close this window.</div>
5+
}
6+
7+
@if (isDebugMode) {
8+
<table class="debug">
9+
@for (param of params() | keyvalue; track param.key) {
10+
<tr>
11+
<td>{{ param.key }}</td>
12+
<td>{{ param.value }}</td>
13+
</tr>
14+
}
15+
</table>
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
div {
2+
padding: 1rem;
3+
text-align: justify;
4+
}
5+
6+
.debug {
7+
margin: 1rem;
8+
font-family: monospace;
9+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {AfterViewInit, Component, computed, effect, inject, isDevMode, signal} from '@angular/core';
2+
import {AppConfig} from '../app-config.service';
3+
import {KeyValuePipe, Location} from '@angular/common';
4+
import {ActivatedRoute, Router} from '@angular/router';
5+
6+
export interface OidcPopupMessage {
7+
oidcParams: [string, string][];
8+
}
9+
10+
@Component({
11+
selector: 'geoengine-oidc-popup',
12+
templateUrl: './oidc-popup.component.html',
13+
styleUrls: ['./oidc-popup.component.scss'],
14+
imports: [KeyValuePipe],
15+
})
16+
export class OidcPopupComponent implements AfterViewInit {
17+
protected readonly config = inject<AppConfig>(AppConfig);
18+
19+
readonly params = signal<Map<string, string>>(new Map());
20+
21+
protected readonly location = inject(Location);
22+
protected readonly router = inject(Router);
23+
protected readonly route = inject(ActivatedRoute);
24+
25+
readonly isError = computed(() => this.params().has('error'));
26+
readonly isDebugMode = isDevMode();
27+
28+
constructor() {
29+
effect(() => {
30+
const params = this.params();
31+
if (params.size === 0) return;
32+
33+
window.postMessage({oidcParams: Array.from(params.entries())} as OidcPopupMessage, '*');
34+
});
35+
}
36+
37+
ngAfterViewInit(): void {
38+
const params = new Map<string, string>();
39+
Object.entries(this.route.snapshot.queryParams).forEach(([key, value]) => {
40+
params.set(key, value as string);
41+
});
42+
this.params.set(params);
43+
}
44+
}

projects/manager/src/app/providers/provider-editor/forms/aruna/aruna.component.html

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,11 @@
4343
<mat-form-field>
4444
<mat-label>Listing priority</mat-label>
4545
<input matInput formControlName="priority" [errorStateMatcher]="errorStateMatcher" />
46-
@if (priority.hasError('min')) {
47-
<mat-error> Priority must be at least -32768 </mat-error>
48-
}
49-
@if (priority.hasError('max')) {
50-
<mat-error> Priority must not exceed 32767 </mat-error>
46+
@if (priority.hasError('outOfRange')) {
47+
<mat-error>Priority must be between -32768 and 32767</mat-error>
5148
}
5249
@if (priority.hasError('notInteger')) {
53-
<mat-error> Priority must be a number </mat-error>
50+
<mat-error>Priority must be a number</mat-error>
5451
}
5552
</mat-form-field>
5653
</mat-card-content>

projects/manager/src/app/providers/provider-editor/forms/aruna/aruna.component.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {MatInput, MatLabel} from '@angular/material/input';
1919
import {CdkTextareaAutosize} from '@angular/cdk/text-field';
2020
import {MatTooltip} from '@angular/material/tooltip';
2121
import {ErrorStateMatcher} from '@angular/material/core';
22+
import {priorityValidator} from '../util/validators';
2223

2324
@Component({
2425
selector: 'geoengine-manager-aruna-editor-form',
@@ -78,11 +79,7 @@ export class ArunaComponent {
7879
Validators.max(31536000),
7980
this.integerValidator(),
8081
]),
81-
priority: this.fb.nonNullable.control<number | null | undefined>(0, [
82-
Validators.min(-32768),
83-
Validators.max(32767),
84-
this.integerValidator(),
85-
]),
82+
priority: this.fb.nonNullable.control<number | null | undefined>(0, [priorityValidator()]),
8683
});
8784

8885
effect(() => {
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<mat-form-field>
22
<mat-label>Id</mat-label>
3-
<input matInput readonly [formControl]="idControl" [disabled]="disabled" (blur)="onTouched()" />
4-
<button mat-button (click)="generate()">Generate</button>
3+
<input matInput readonly [formControl]="idControl" (blur)="onTouched()" />
4+
<button mat-button (click)="generate()" [disabled]="isDisabled()">Generate</button>
55
</mat-form-field>

projects/manager/src/app/providers/provider-editor/forms/util/id-input/id-input.component.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import {AfterViewInit, Component, forwardRef} from '@angular/core';
1+
import {AfterViewInit, Component, effect, forwardRef, signal} from '@angular/core';
22
import {v4 as uuidv4} from 'uuid';
33
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule} from '@angular/forms';
44
import {MatFormField} from '@angular/material/form-field';
55
import {MatInput, MatLabel} from '@angular/material/input';
66
import {MatButton} from '@angular/material/button';
7+
import {UUID} from '@geoengine/common';
8+
import {toSignal} from '@angular/core/rxjs-interop';
79

810
@Component({
911
selector: 'geoengine-manager-id-input',
@@ -18,10 +20,21 @@ import {MatButton} from '@angular/material/button';
1820
],
1921
imports: [ReactiveFormsModule, MatFormField, MatInput, MatButton, MatLabel],
2022
})
21-
export class IdInputComponent implements AfterViewInit, ControlValueAccessor {
22-
idControl = new FormControl<string>('');
23+
export class IdInputComponent implements ControlValueAccessor, AfterViewInit {
24+
readonly idControl = new FormControl<UUID>('', {nonNullable: true});
25+
26+
readonly isDisabled = signal(false);
27+
28+
constructor() {
29+
const valueChanged = toSignal<UUID | undefined>(this.idControl.valueChanges, {initialValue: undefined});
30+
31+
effect(() => {
32+
const newValue = valueChanged();
33+
if (!newValue) return;
34+
this.onChange(newValue);
35+
});
36+
}
2337

24-
protected disabled = false;
2538
protected onTouched: () => void = () => {
2639
/* do nothing */
2740
};
@@ -34,24 +47,19 @@ export class IdInputComponent implements AfterViewInit, ControlValueAccessor {
3447
if (!this.idControl.value) {
3548
this.generate();
3649
}
37-
38-
this.idControl.valueChanges.subscribe((value) => {
39-
if (value) {
40-
this.onChange(value);
41-
}
42-
});
4350
}
4451

4552
generate(): void {
4653
const newId = uuidv4();
4754
this.idControl.patchValue(newId);
48-
this.onChange(newId);
4955
}
5056

51-
writeValue(value: string): void {
52-
if (value) {
53-
this.idControl.patchValue(value, {emitEvent: false});
57+
writeValue(value: unknown): void {
58+
if (typeof value !== 'string') {
59+
throw new Error('Value must be a string');
5460
}
61+
62+
this.idControl.patchValue(value, {emitEvent: false});
5563
}
5664

5765
registerOnChange(fn: (value: string) => void): void {
@@ -63,7 +71,7 @@ export class IdInputComponent implements AfterViewInit, ControlValueAccessor {
6371
}
6472

6573
setDisabledState(isDisabled: boolean): void {
66-
this.disabled = isDisabled;
74+
this.isDisabled.set(isDisabled);
6775
if (isDisabled) {
6876
this.idControl.disable();
6977
} else {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms';
2+
3+
export const priorityValidator =
4+
(): ValidatorFn =>
5+
(control: AbstractControl): ValidationErrors | null => {
6+
const value = Number(control.value);
7+
8+
if (!Number.isInteger(value)) {
9+
return {notInteger: true};
10+
}
11+
12+
if (value < -32768 || value > 32767) {
13+
return {outOfRange: true};
14+
}
15+
16+
return null;
17+
};

0 commit comments

Comments
 (0)