Skip to content

Commit

Permalink
Release 3.39.3
Browse files Browse the repository at this point in the history
  • Loading branch information
sleidig authored Aug 3, 2024
2 parents 39e9649 + 840cffd commit 28500e1
Show file tree
Hide file tree
Showing 27 changed files with 453 additions and 188 deletions.
72 changes: 0 additions & 72 deletions src/app/app-initializers.ts

This file was deleted.

47 changes: 9 additions & 38 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,8 @@

import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import {
APP_INITIALIZER,
ErrorHandler,
Inject,
LOCALE_ID,
NgModule,
} from "@angular/core";
import { LOCALE_ID, NgModule } from "@angular/core";
import { HttpClientModule } from "@angular/common/http";
import * as Sentry from "@sentry/angular";

import { AppComponent } from "./app.component";
import { allRoutes } from "./app.routing";
Expand All @@ -40,8 +33,6 @@ import {
import { environment } from "../environments/environment";
import { AnalyticsService } from "./core/analytics/analytics.service";
import { ConfigurableEnumModule } from "./core/basic-datatypes/configurable-enum/configurable-enum.module";
import { MatPaginatorIntl } from "@angular/material/paginator";
import { TranslatableMatPaginator } from "./core/language/TranslatableMatPaginator";
import { FaIconLibrary } from "@fortawesome/angular-fontawesome";
import { fas } from "@fortawesome/free-solid-svg-icons";
import { far } from "@fortawesome/free-regular-svg-icons";
Expand Down Expand Up @@ -81,20 +72,20 @@ import { HistoricalDataModule } from "./features/historical-data/historical-data
import { MatchingEntitiesModule } from "./features/matching-entities/matching-entities.module";
import { ProgressDashboardWidgetModule } from "./features/dashboard-widgets/progress-dashboard-widget/progress-dashboard-widget.module";
import { ReportingModule } from "./features/reporting/reporting.module";
import { Router, RouterModule } from "@angular/router";
import { RouterModule } from "@angular/router";
import { TodosModule } from "./features/todos/todos.module";
import moment from "moment";
import { getLocaleFirstDayOfWeek } from "@angular/common";
import { waitForChangeTo } from "./core/session/session-states/session-utils";
import { LoginState } from "./core/session/session-states/login-state.enum";
import { appInitializers } from "./app-initializers";
import { APP_INITIALIZER_PROPAGATE_CONFIG_UPDATES } from "./core/config/config.app-initializer";
import { ImportModule } from "./core/import/import.module";
import { ShortcutDashboardWidgetModule } from "./features/dashboard-widgets/shortcut-dashboard-widget/shortcut-dashboard-widget.module";
import { EntityCountDashboardWidgetModule } from "./features/dashboard-widgets/entity-count-dashboard-widget/entity-count-dashboard-widget.module";
import { BirthdayDashboardWidgetModule } from "./features/dashboard-widgets/birthday-dashboard-widget/birthday-dashboard-widget.module";
import { MarkdownPageModule } from "./features/markdown-page/markdown-page.module";
import { LoginStateSubject } from "./core/session/session-type";
import { AdminModule } from "./core/admin/admin.module";
import { Logging } from "./core/logging/logging.service";
import { APP_INITIALIZER_DEMO_DATA } from "./core/demo-data/demo-data.app-initializer";

/**
* Main entry point of the application.
Expand Down Expand Up @@ -147,23 +138,7 @@ import { AdminModule } from "./core/admin/admin.module";
MatDialogModule,
],
providers: [
/* Sentry setup */
{
provide: ErrorHandler,
useValue: Sentry.createErrorHandler(),
},
{
provide: Sentry.TraceService,
deps: [Router],
},
{
provide: APP_INITIALIZER,
useFactory: () => () => {},
deps: [Sentry.TraceService],
multi: true,
},

{ provide: MatPaginatorIntl, useValue: TranslatableMatPaginator() },
...Logging.getAngularTracingProviders(),
{ provide: ComponentRegistry, useValue: componentRegistry },
{ provide: EntityRegistry, useValue: entityRegistry },
{ provide: WINDOW_TOKEN, useValue: window },
Expand All @@ -190,17 +165,13 @@ import { AdminModule } from "./core/admin/admin.module";
}),
deps: [LoginStateSubject],
},
appInitializers,
APP_INITIALIZER_PROPAGATE_CONFIG_UPDATES,
APP_INITIALIZER_DEMO_DATA,
],
bootstrap: [AppComponent],
})
export class AppModule {
constructor(icons: FaIconLibrary, @Inject(LOCALE_ID) locale: string) {
constructor(icons: FaIconLibrary) {
icons.addIconPacks(fas, far);
moment.updateLocale(moment.locale(), {
week: {
dow: getLocaleFirstDayOfWeek(locale),
},
});
}
}
10 changes: 9 additions & 1 deletion src/app/core/analytics/analytics.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import {
import { RouterTestingModule } from "@angular/router/testing";
import { ConfigService } from "../config/config.service";
import { UsageAnalyticsConfig } from "./usage-analytics-config";
import { Subject } from "rxjs";
import { BehaviorSubject, Subject } from "rxjs";
import { Config } from "../config/config";
import { SiteSettingsService } from "../site-settings/site-settings.service";
import { LoginStateSubject } from "../session/session-type";
import { SessionSubject } from "../session/auth/session-info";
import { LoginState } from "../session/session-states/login-state.enum";

describe("AnalyticsService", () => {
let service: AnalyticsService;
Expand Down Expand Up @@ -47,6 +50,11 @@ describe("AnalyticsService", () => {
provide: SiteSettingsService,
useValue: { siteName: siteNameSubject },
},
{
provide: LoginStateSubject,
useValue: new BehaviorSubject(LoginState.LOGGED_IN),
},
{ provide: SessionSubject, useValue: new BehaviorSubject(undefined) },
],
});
service = TestBed.inject(AnalyticsService);
Expand Down
23 changes: 22 additions & 1 deletion src/app/core/analytics/analytics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import {
} from "./usage-analytics-config";
import { Angulartics2, Angulartics2Matomo } from "angulartics2";
import md5 from "md5";
import { LoginState } from "../session/session-states/login-state.enum";
import { LoginStateSubject } from "../session/session-type";
import { SessionSubject } from "../session/auth/session-info";

/**
* Track usage analytics data and report it to a backend server like Matomo.
Expand All @@ -23,7 +26,25 @@ export class AnalyticsService {
private angulartics2: Angulartics2,
private angulartics2Matomo: Angulartics2Matomo,
private configService: ConfigService,
) {}
loginState: LoginStateSubject,
private sessionInfo: SessionSubject,
) {
if (environment.production) {
this.init();
}

// update the user context for remote error logging and tracking and load config initially
loginState.subscribe((s: LoginState) => this.updateSessionInfo(s));
}

private updateSessionInfo(newState: LoginState): void {
if (newState === LoginState.LOGGED_IN) {
const username = this.sessionInfo.value?.name;
this.setUser(username);
} else {
this.setUser(undefined);
}
}

/**
* Sets a unique user hash which is always for the same user but does not expose the username.
Expand Down
27 changes: 27 additions & 0 deletions src/app/core/config/config.app-initializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { APP_INITIALIZER } from "@angular/core";
import { ConfigService } from "./config.service";
import { RouterService } from "./dynamic-routing/router.service";
import { EntityConfigService } from "../entity/entity-config.service";
import { Router } from "@angular/router";

export const APP_INITIALIZER_PROPAGATE_CONFIG_UPDATES = {
provide: APP_INITIALIZER,
useFactory:
(
configService: ConfigService,
routerService: RouterService,
entityConfigService: EntityConfigService,
router: Router,
) =>
async () => {
// Re-trigger services that depend on the config when something changes
configService.configUpdates.subscribe(() => {
routerService.initRouting();
entityConfigService.setupEntitiesFromConfig();
const url = location.href.replace(location.origin, "");
router.navigateByUrl(url, { skipLocationChange: true });
});
},
deps: [ConfigService, RouterService, EntityConfigService, Router],
multi: true,
};
25 changes: 25 additions & 0 deletions src/app/core/database/sync.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,25 @@ import { LoginStateSubject, SyncStateSubject } from "../session/session-type";
import { LoginState } from "../session/session-states/login-state.enum";
import { KeycloakAuthService } from "../session/auth/keycloak/keycloak-auth.service";
import { Subject } from "rxjs";
import { NAVIGATOR_TOKEN } from "../../utils/di-tokens";

describe("SyncService", () => {
let service: SyncService;
let loginState: LoginStateSubject;
let mockAuthService: jasmine.SpyObj<KeycloakAuthService>;
let mockNavigator;

beforeEach(() => {
mockAuthService = jasmine.createSpyObj(["login", "addAuthHeader"]);
mockNavigator = { onLine: true };

TestBed.configureTestingModule({
providers: [
{ provide: KeycloakAuthService, useValue: mockAuthService },
{ provide: Database, useClass: PouchDatabase },
LoginStateSubject,
SyncStateSubject,
{ provide: NAVIGATOR_TOKEN, useValue: mockNavigator },
],
});
service = TestBed.inject(SyncService);
Expand Down Expand Up @@ -94,4 +99,24 @@ describe("SyncService", () => {

stopPeriodicTimer();
}));

it("should skip sync calls when offline", fakeAsync(() => {
const mockLocalDb = jasmine.createSpyObj(["sync"]);
mockLocalDb.sync.and.resolveTo({});
const db = TestBed.inject(Database) as PouchDatabase;
spyOn(db, "getPouchDB").and.returnValue(mockLocalDb);

mockNavigator.onLine = false;

service.startSync();

tick(1000);
expect(mockLocalDb.sync).not.toHaveBeenCalled();

mockNavigator.onLine = true;
tick(SyncService.SYNC_INTERVAL);
expect(mockLocalDb.sync).toHaveBeenCalled();

stopPeriodicTimer();
}));
});
10 changes: 9 additions & 1 deletion src/app/core/database/sync.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from "@angular/core";
import { Inject, Injectable } from "@angular/core";
import { Database } from "./database";
import { PouchDatabase } from "./pouch-database";
import { Logging } from "../logging/logging.service";
Expand All @@ -16,6 +16,7 @@ import { Config } from "../config/config";
import { Entity } from "../entity/model/entity";
import { from, interval, merge, of } from "rxjs";
import { environment } from "../../../environments/environment";
import { NAVIGATOR_TOKEN } from "../../utils/di-tokens";

/**
* This service initializes the remote DB and manages the sync between the local and remote DB.
Expand All @@ -36,6 +37,7 @@ export class SyncService {
private database: Database,
private authService: KeycloakAuthService,
private syncStateSubject: SyncStateSubject,
@Inject(NAVIGATOR_TOKEN) private navigator: Navigator,
) {
this.remoteDatabase = new PouchDatabase(this.authService);

Expand Down Expand Up @@ -89,6 +91,12 @@ export class SyncService {
* Execute a (one-time) sync between the local and server database.
*/
sync(): Promise<SyncResult> {
if (!this.navigator.onLine) {
Logging.debug("Not syncing because offline");
this.syncStateSubject.next(SyncState.UNSYNCED);
return Promise.resolve({});
}

this.syncStateSubject.next(SyncState.STARTED);

return this.localDB
Expand Down
24 changes: 24 additions & 0 deletions src/app/core/demo-data/demo-data.app-initializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {
APP_INITIALIZER,
Injector,
ɵcreateInjector as createInjector,
} from "@angular/core";
import { environment } from "../../../environments/environment";

/**
* Provide this in the app module to run the demo data generation with lazy-loading
* (no download of module code if not in demo mode).
*/
export const APP_INITIALIZER_DEMO_DATA = {
provide: APP_INITIALIZER,
useFactory: (injector: Injector) => async () => {
if (environment.demo_mode) {
const m = await import("./demo-data.module");
await createInjector(m.DemoDataModule, injector)
.get(m.DemoDataModule)
.publishDemoData();
}
},
deps: [Injector],
multi: true,
};
2 changes: 1 addition & 1 deletion src/app/core/entity/latest-entity-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export abstract class LatestEntityLoader<T extends Entity> {
} catch (err) {
if (err?.status !== HttpStatusCode.NotFound) {
Logging.error(
`Loading entity "${this.entityCtor.ENTITY_TYPE}:${this.entityID}" failed: ${this.entityID}`,
`Initial loading of entity "${this.entityCtor.ENTITY_TYPE}:${this.entityID}" failed [Service based on LatestEntityLoader]`,
err,
);
}
Expand Down
Loading

0 comments on commit 28500e1

Please sign in to comment.