Skip to content

Commit

Permalink
Frontend exchange configuration with backend
Browse files Browse the repository at this point in the history
  • Loading branch information
DraTeots committed Jul 27, 2024
1 parent c9138d7 commit 9bad737
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 11 deletions.
42 changes: 36 additions & 6 deletions firebird-ng/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions firebird-ng/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@types/picomatch": "^2.3.3",
"angular-split": "^17.2.0",
"jsdom": "^24.0.0",
"jsonc-parser": "^3.3.1",
"jsrootdi": "^7.6.101",
"jszip": "^3.10.1",
"lil-gui": "^0.19.2",
Expand Down
17 changes: 15 additions & 2 deletions firebird-ng/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import {APP_INITIALIZER, ApplicationConfig, importProvidersFrom} from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import {provideAnimations} from "@angular/platform-browser/animations";
import {FirebirdConfigService} from "./firebird-config.service";
import {provideHttpClient, withFetch} from "@angular/common/http";

export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideAnimations()
provideAnimations(),
provideHttpClient(withFetch()),
{
provide: APP_INITIALIZER,
useFactory: configInitializer,
deps: [FirebirdConfigService],
multi: true
}
]
};

export function configInitializer(configService: FirebirdConfigService): () => Promise<any> {
return () => configService.loadConfig();
}
66 changes: 66 additions & 0 deletions firebird-ng/src/app/firebird-config.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { FirebirdConfigService } from './firebird-config.service';
import * as jsoncParser from 'jsonc-parser';

describe('FirebirdConfigService', () => {
let service: FirebirdConfigService;
let httpMock: HttpTestingController;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [FirebirdConfigService]
});
service = TestBed.inject(FirebirdConfigService);
httpMock = TestBed.inject(HttpTestingController);
});

afterEach(() => {
httpMock.verify(); // Ensure that no requests are outstanding.
});
//
it('should fetch and parse JSONC data correctly', () => {
const dummyConfig = { serverPort: 5001 };
const jsoncData = '{ "key": "value" // comment }';

service.loadConfig().then(()=>{
expect(service.config.serverPort).toBe(5001);
});

// Set up the HttpTestingController
const req = httpMock.expectOne(service['configUrl']);
expect(req.request.method).toBe('GET');
req.flush('{ "serverPort": 5001, "useAuthentication": true, "logLevel": "info" }'); // Mock the HTTP response

});
//
// it('should handle HTTP errors gracefully', () => {
// const errorResponse = new ErrorEvent('Network error');
//
// service.getConfig().subscribe({
// next: config => fail('should have failed with the network error'),
// error: error => expect(error).toBeTruthy(),
// complete: () => fail('The request should not complete successfully')
// });
//
// });
});


// import { TestBed } from '@angular/core/testing';
//
// import { FirebirdConfigService } from './firebird-config.service';
//
// describe('FirebirdConfigService', () => {
// let service: FirebirdConfigService;
//
// beforeEach(() => {
// TestBed.configureTestingModule({});
// service = TestBed.inject(FirebirdConfigService);
// });
//
// it('should be created', () => {
// expect(service).toBeTruthy();
// });
// });
73 changes: 73 additions & 0 deletions firebird-ng/src/app/firebird-config.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as jsoncParser from 'jsonc-parser';
import {deepCopy} from "./utils/deep-copy";
import {BehaviorSubject, Observable, catchError, map, of, firstValueFrom} from "rxjs";


export interface FirebirdConfig {
serverPort: number;
serverHost: string;
servedByPyrobird: boolean;
apiAvailable: boolean;
useAuthentication: boolean;
logLevel: string;
}

export const defaultFirebirdConfig: FirebirdConfig = {
serverPort: 5454,
serverHost: "localhost",
apiAvailable: false,
servedByPyrobird: false,
useAuthentication: true,
logLevel: 'info'
};


@Injectable({
providedIn: 'root'
})
export class FirebirdConfigService {
private configUrl = 'assets/config.jsonc'; // URL to the JSONC config file
private _config = deepCopy(defaultFirebirdConfig);

private triedLoading = false;

constructor(private http: HttpClient) {}

get config(): FirebirdConfig {
if (!this.triedLoading) {
this.triedLoading = true;
console.error("Client called config while config is not loaded.")
}
return this._config;
}

async loadConfig(): Promise<void> {
try {

const jsoncData = await firstValueFrom(
this.http.get(this.configUrl, { responseType: 'text' })
);
const loadedConfig = this.parseConfig(jsoncData);

// Merge loadedConfig over default config
this._config = { ...defaultFirebirdConfig, ...loadedConfig };
} catch (error) {
console.error(`Failed to load config: ${error}`);
console.log(`Default config will be used`);
} finally {
this.triedLoading = true;
}
}


private parseConfig(jsoncData: string): Partial<FirebirdConfig> {
try {
return jsoncParser.parse(jsoncData);
} catch (parseError) {
console.error('Error parsing JSONC data', parseError);
return {};
}
}
}
47 changes: 47 additions & 0 deletions firebird-ng/src/app/input-config/input-config.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,52 @@ <h6 class="mb-0">API Port:</h6>
<button type="button" class="btn btn-lg btn-primary" [routerLink]="['/display']">DISPLAY</button>
</div>

<mat-accordion class="mt-4">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Backend details
</mat-panel-title>
</mat-expansion-panel-header>
<div>
<table class="table">
<thead>
<tr>
<th scope="col">Property</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Server Port</td>
<td>{{ firebirdConfig.serverPort }}</td>
</tr>
<tr>
<td>Server Host</td>
<td>{{ firebirdConfig.serverHost }}</td>
</tr>
<tr>
<td>Served by Pyrobird</td>
<td>{{ firebirdConfig.servedByPyrobird ? 'Yes' : 'No' }}</td>
</tr>
<tr>
<td>API Available</td>
<td>{{ firebirdConfig.apiAvailable ? 'Yes' : 'No' }}</td>
</tr>
<tr>
<td>Use Authentication</td>
<td>{{ firebirdConfig.useAuthentication ? 'Yes' : 'No' }}</td>
</tr>
<tr>
<td>Log Level</td>
<td>{{ firebirdConfig.logLevel }}</td>
</tr>
</tbody>
</table>
</div>
</mat-expansion-panel>
</mat-accordion>
<br>

</form>
</div>
13 changes: 10 additions & 3 deletions firebird-ng/src/app/input-config/input-config.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@ import {MatCard, MatCardContent, MatCardTitle} from "@angular/material/card";
import {MatSlideToggle} from "@angular/material/slide-toggle";
import {MatFormField} from "@angular/material/form-field";
import {MatInput, MatLabel} from "@angular/material/input";
import {map, Observable, startWith} from "rxjs";
import {config, map, Observable, startWith} from "rxjs";
import {MatAutocomplete, MatAutocompleteTrigger, MatOption} from "@angular/material/autocomplete";
import {AsyncPipe, NgForOf} from "@angular/common";
import {MatTooltip} from "@angular/material/tooltip";
import {ResourceSelectComponent} from "../resource-select/resource-select.component";
import {defaultFirebirdConfig, FirebirdConfig, FirebirdConfigService} from "../firebird-config.service";
import {MatAccordion, MatExpansionPanel, MatExpansionPanelTitle, MatExpansionPanelHeader} from "@angular/material/expansion";



@Component({
selector: 'app-input-config',
standalone: true,
imports: [ReactiveFormsModule, RouterLink, MatCard, MatCardContent, MatCardTitle, MatSlideToggle, MatFormField, MatInput, MatLabel, MatAutocompleteTrigger, MatAutocomplete, MatOption, AsyncPipe, MatTooltip, NgForOf, ResourceSelectComponent],
imports: [ReactiveFormsModule, RouterLink, MatCard, MatCardContent, MatCardTitle, MatSlideToggle, MatFormField, MatInput, MatLabel, MatAutocompleteTrigger, MatAutocomplete, MatOption, AsyncPipe, MatTooltip, NgForOf, ResourceSelectComponent, MatAccordion, MatExpansionPanel, MatExpansionPanelTitle, MatExpansionPanelHeader],
templateUrl: './input-config.component.html',
styleUrl: './input-config.component.scss'
})
Expand All @@ -32,6 +34,7 @@ export class InputConfigComponent implements OnInit, AfterViewInit {
serverUseApi: FormControl<boolean | null> = new FormControl(false);
serverApiHost = new FormControl('localhost');
serverApiPort: FormControl<number | null> = new FormControl(5454);
firebirdConfig: FirebirdConfig = defaultFirebirdConfig;


@ViewChild('geometrySelect')
Expand Down Expand Up @@ -81,7 +84,8 @@ export class InputConfigComponent implements OnInit, AfterViewInit {
];


constructor(private configService: UserConfigService) {
constructor(private configService: UserConfigService,
private firebirdConfigService: FirebirdConfigService) {
}


Expand Down Expand Up @@ -117,5 +121,8 @@ export class InputConfigComponent implements OnInit, AfterViewInit {
this.bindConfigToControl(this.serverUseApi, this.configService.localServerUseApi);
this.bindConfigToControl(this.serverApiHost, this.configService.localServerHost);
this.bindConfigToControl(this.serverApiPort, this.configService.localServerPort);

this.firebirdConfig = this.firebirdConfigService.config;

}
}
Loading

0 comments on commit 9bad737

Please sign in to comment.