Skip to content

Commit

Permalink
fix(core): better debugging details in logs and support view (#1832)
Browse files Browse the repository at this point in the history
* Better logging for database conflicts
* Document count in support panel
  • Loading branch information
TheSlimvReal authored Apr 18, 2023
1 parent f9d455f commit 2bba145
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 17 deletions.
4 changes: 3 additions & 1 deletion src/app/core/database/pouch-database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,9 @@ export class PouchDatabase extends Database {
newObject._rev = existingObject._rev;
return this.put(newObject);
} else {
existingError.message = existingError.message + " (unable to resolve)";
existingError.message = `${
existingError.message
} (unable to resolve) ID: ${JSON.stringify(newObject)}`;
throw new DatabaseException(existingError);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/app/core/support/support/support.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ <h1>Technical User Support Details</h1>
<td>Storage usage</td>
<td>{{ storageInfo || 'No information' }}</td>
</tr>
<tr>
<td>Database documents</td>
<td>{{ dbInfo }}</td>
</tr>
<tr>
<td>Service Worker</td>
<td>{{ swStatus }}</td>
Expand Down
21 changes: 13 additions & 8 deletions src/app/core/support/support/support.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import {
fakeAsync,
TestBed,
tick,
waitForAsync,
} from "@angular/core/testing";

import { SupportComponent } from "./support.component";
import { SessionService } from "../../session/session-service/session.service";
import { BehaviorSubject, of } from "rxjs";
import { SyncState } from "../../session/session-states/sync-state.enum";
import { SwUpdate } from "@angular/service-worker";
import { Database } from "../../database/database";
import { LOCATION_TOKEN, WINDOW_TOKEN } from "../../../utils/di-tokens";
import { TEST_USER } from "../../../utils/mocked-testing.module";
import { RemoteSession } from "../../session/session-service/remote-session";
Expand All @@ -20,14 +20,15 @@ import { SyncedSessionService } from "../../session/session-service/synced-sessi
import { MatDialogModule } from "@angular/material/dialog";
import { HttpClientTestingModule } from "@angular/common/http/testing";
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { PouchDatabase } from "../../database/pouch-database";

describe("SupportComponent", () => {
let component: SupportComponent;
let fixture: ComponentFixture<SupportComponent>;
const testUser = { name: TEST_USER, roles: [] };
let mockSessionService: jasmine.SpyObj<SessionService>;
const mockSW = { isEnabled: false };
let mockDB: jasmine.SpyObj<Database>;
let mockDB: jasmine.SpyObj<PouchDatabase>;
const mockWindow = {
navigator: {
userAgent: "mock user agent",
Expand All @@ -42,7 +43,10 @@ describe("SupportComponent", () => {
syncState: new BehaviorSubject(SyncState.UNSYNCED),
});
mockSessionService.getCurrentUser.and.returnValue(testUser);
mockDB = jasmine.createSpyObj(["destroy"]);
mockDB = jasmine.createSpyObj(["destroy", "getPouchDB"]);
mockDB.getPouchDB.and.returnValue({
info: () => Promise.resolve({ doc_count: 1, update_seq: 2 }),
} as any);
mockLocation = jasmine.createSpyObj(["reload"]);
await TestBed.configureTestingModule({
imports: [
Expand All @@ -54,18 +58,18 @@ describe("SupportComponent", () => {
providers: [
{ provide: SessionService, useValue: mockSessionService },
{ provide: SwUpdate, useValue: mockSW },
{ provide: Database, useValue: mockDB },
{ provide: PouchDatabase, useValue: mockDB },
{ provide: WINDOW_TOKEN, useValue: mockWindow },
{ provide: LOCATION_TOKEN, useValue: mockLocation },
],
}).compileComponents();
});

beforeEach(() => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(SupportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
}));

it("should create", () => {
expect(component).toBeTruthy();
Expand All @@ -78,15 +82,16 @@ describe("SupportComponent", () => {
expect(component.lastRemoteLogin).toBe("never");
expect(component.swStatus).toBe("not enabled");
expect(component.userAgent).toBe("mock user agent");
expect(component.dbInfo).toBe("1 (update sequence 2)");
});

it("should correctly read sync and remote login status from local storage", () => {
it("should correctly read sync and remote login status from local storage", async () => {
const lastSync = new Date("2022-01-01").toISOString();
localStorage.setItem(SyncedSessionService.LAST_SYNC_KEY, lastSync);
const lastRemoteLogin = new Date("2022-01-02").toISOString();
localStorage.setItem(RemoteSession.LAST_LOGIN_KEY, lastRemoteLogin);

component.ngOnInit();
await component.ngOnInit();

expect(component.lastSync).toBe(lastSync);
expect(component.lastRemoteLogin).toBe(lastRemoteLogin);
Expand Down
26 changes: 18 additions & 8 deletions src/app/core/support/support/support.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { SessionService } from "../../session/session-service/session.service";
import { LOCATION_TOKEN, WINDOW_TOKEN } from "../../../utils/di-tokens";
import { SyncState } from "../../session/session-states/sync-state.enum";
import { SwUpdate } from "@angular/service-worker";
import { Database } from "../../database/database";
import * as Sentry from "@sentry/browser";
import { RemoteSession } from "../../session/session-service/remote-session";
import { ConfirmationDialogService } from "../../confirmation-dialog/confirmation-dialog.service";
Expand All @@ -14,16 +13,14 @@ import { AuthUser } from "../../session/session-service/auth-user";
import { firstValueFrom } from "rxjs";
import { MatExpansionModule } from "@angular/material/expansion";
import { MatButtonModule } from "@angular/material/button";
import { PouchDatabase } from "../../database/pouch-database";

@Component({
selector: "app-support",
templateUrl: "./support.component.html",
styleUrls: ["./support.component.scss"],
imports: [
MatExpansionModule,
MatButtonModule
],
standalone: true
imports: [MatExpansionModule, MatButtonModule],
standalone: true,
})
export class SupportComponent implements OnInit {
currentUser: AuthUser;
Expand All @@ -35,25 +32,27 @@ export class SupportComponent implements OnInit {
swLog = "not available";
userAgent = this.window.navigator.userAgent;
appVersion: string;
dbInfo: string;

constructor(
private sessionService: SessionService,
private sw: SwUpdate,
private database: Database,
private database: PouchDatabase,
private confirmationDialog: ConfirmationDialogService,
private http: HttpClient,
@Inject(WINDOW_TOKEN) private window: Window,
@Inject(LOCATION_TOKEN) private location: Location
) {}

ngOnInit(): void {
ngOnInit() {
this.currentUser = this.sessionService.getCurrentUser();
this.appVersion = environment.appVersion;
this.initCurrentSyncState();
this.initLastSync();
this.initLastRemoteLogin();
this.initStorageInfo();
this.initSwStatus();
return this.initDbInfo();
}

private initCurrentSyncState() {
Expand Down Expand Up @@ -103,6 +102,16 @@ export class SupportComponent implements OnInit {
.then((res) => (this.swLog = res));
}

private initDbInfo() {
return this.database
.getPouchDB()
.info()
.then(
(res) =>
(this.dbInfo = `${res.doc_count} (update sequence ${res.update_seq})`)
);
}

sendReport() {
// This is sent even without submitting the crash report.
Sentry.captureMessage("report information", {
Expand All @@ -116,6 +125,7 @@ export class SupportComponent implements OnInit {
userAgent: this.userAgent,
swLog: this.swLog,
storageInfo: this.storageInfo,
dbInfo: this.dbInfo,
},
});
Sentry.showReportDialog({
Expand Down

0 comments on commit 2bba145

Please sign in to comment.