Skip to content

Commit e39597d

Browse files
committed
Improve developer diagnostics
1 parent 0d57a51 commit e39597d

8 files changed

Lines changed: 110 additions & 84 deletions

File tree

src/SIL.XForge.Scripture/ClientApp/src/app/app-routing.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ServalAdminAuthGuard } from './serval-administration/serval-admin-auth.
1313
import { ServalAdministrationComponent } from './serval-administration/serval-administration.component';
1414
import { ServalProjectComponent } from './serval-administration/serval-project.component';
1515
import { SettingsComponent } from './settings/settings.component';
16+
import { BlankPageComponent } from './shared/blank-page/blank-page.component';
1617
import { PageNotFoundComponent } from './shared/page-not-found/page-not-found.component';
1718
import { SettingsAuthGuard, SyncAuthGuard } from './shared/project-router.guard';
1819
import { SyncComponent } from './sync/sync.component';
@@ -31,6 +32,7 @@ const routes: Routes = [
3132
{ path: 'serval-administration/:projectId', component: ServalProjectComponent, canActivate: [ServalAdminAuthGuard] },
3233
{ path: 'serval-administration', component: ServalAdministrationComponent, canActivate: [ServalAdminAuthGuard] },
3334
{ path: 'system-administration', component: SystemAdministrationComponent, canActivate: [SystemAdminAuthGuard] },
35+
{ path: 'blank-page', component: BlankPageComponent },
3436
{ path: '**', component: PageNotFoundComponent }
3537
];
3638

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>This component is intentionally blank in order to test application behavior when no data should be loaded.</p>

src/SIL.XForge.Scripture/ClientApp/src/app/shared/blank-page/blank-page.component.scss

Whitespace-only changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'app-blank-page',
5+
standalone: true,
6+
template: `<p>
7+
This component is intentionally blank in order to test application behavior when almost no data should be loaded.
8+
</p>`
9+
})
10+
export class BlankPageComponent {}
Lines changed: 55 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{{ digestCycleCounter }}
2+
13
<div class="wrapper" [class.collapsed]="!isExpanded">
24
<div class="header">
35
@if (isExpanded) {
@@ -15,88 +17,60 @@ <h2>Developer Diagnostics</h2>
1517
</button>
1618
</div>
1719
@if (isExpanded) {
18-
<h3>{{ totalDocsCount | l10nNumber }} documents tracked by realtime service</h3>
19-
<table>
20-
<thead>
21-
<tr>
22-
<th>Collection</th>
23-
<th>Docs</th>
24-
<th>Subscribers</th>
25-
<th>Active Subs</th>
26-
</tr>
27-
</thead>
28-
<tbody>
29-
@for (docType of docCountsByCollection | keyvalue; track docType.key) {
30-
<tr>
31-
<td>{{ docType.key }}</td>
32-
<td>{{ docType.value.docs | l10nNumber }}</td>
33-
<td>{{ docType.value.subscribers | l10nNumber }}</td>
34-
<td>{{ docType.value.activeDocSubscriptionsCount | l10nNumber }}</td>
35-
</tr>
36-
}
37-
</tbody>
38-
</table>
39-
40-
<h3>Realtime doc subscribers</h3>
41-
<table>
42-
<thead>
43-
<tr>
44-
<th>Collection</th>
45-
<th>Context</th>
46-
<th>Subs</th>
47-
<th>Active</th>
48-
</tr>
49-
</thead>
50-
<tbody>
51-
@for (collection of subscriberCountsByContext | keyvalue; track collection.key) {
52-
@for (doc of collection.value | keyvalue; track doc.key; let first = $first; let count = $count) {
53-
<tr>
54-
@if (first) {
55-
<th [attr.rowspan]="count">{{ collection.key }}</th>
20+
<div class="nav-and-content-wrapper">
21+
<div class="nav-wrapper">
22+
<span (click)="tab = 0" [class.active]="tab === 0">Realtime server</span>
23+
<span (click)="tab = 1" [class.active]="tab === 1">Loading</span>
24+
<span (click)="tab = 2" [class.active]="tab === 2">Digest cycles</span>
25+
</div>
26+
<div>
27+
@if (tab === 0) {
28+
<h3>{{ totalDocsCount | l10nNumber }} documents tracked by realtime service</h3>
29+
<table>
30+
<thead>
31+
<tr>
32+
<th>Collection</th>
33+
<th>Docs</th>
34+
<th>Subscribers</th>
35+
<th>Queries</th>
36+
</tr>
37+
</thead>
38+
<tbody>
39+
@for (docType of docCountsByCollection | keyvalue; track docType.key) {
40+
<tr>
41+
<td>{{ docType.key }}</td>
42+
<td>{{ docType.value.docs | l10nNumber }}</td>
43+
<td>{{ docType.value.subscribers | l10nNumber }}</td>
44+
<td>{{ docType.value.queries | l10nNumber }}</td>
45+
</tr>
5646
}
57-
<td>{{ doc.key }}</td>
58-
<td>{{ doc.value.all | l10nNumber }}</td>
59-
<td>{{ doc.value.active | l10nNumber }}</td>
60-
</tr>
61-
}
62-
}
63-
</tbody>
64-
</table>
65-
66-
<h3>Realtime queries</h3>
67-
<table>
68-
<thead>
69-
<tr>
70-
<th>Collection</th>
71-
<th>Queries</th>
72-
</tr>
73-
</thead>
74-
<tbody>
75-
@for (docType of queriesByCollection | keyvalue; track docType.key) {
76-
<tr>
77-
<td>{{ docType.key }}</td>
78-
<td>{{ docType.value | l10nNumber }}</td>
79-
</tr>
80-
}
81-
</tbody>
82-
</table>
83-
84-
<h3>Components affecting loading indicator</h3>
85-
<table>
86-
<thead>
87-
<tr>
88-
<th>Component</th>
89-
<th>Count</th>
90-
</tr>
91-
</thead>
92-
<tbody>
93-
@for (component of noticeService.loadingCountsByCallerId | keyvalue; track component.key) {
94-
<tr [class.bold]="component.value > 0">
95-
<td>{{ component.key }}</td>
96-
<td>{{ component.value | l10nNumber }}</td>
97-
</tr>
47+
</tbody>
48+
</table>
49+
<h3>Blank page</h3>
50+
<a appRouterLink="/blank-page">Go to blank page</a> (for testing subscriber cleanup)
51+
} @else if (tab === 1) {
52+
<h3>Components affecting loading indicator</h3>
53+
<table>
54+
<thead>
55+
<tr>
56+
<th>Component</th>
57+
<th>Count</th>
58+
</tr>
59+
</thead>
60+
<tbody>
61+
@for (component of noticeService.loadingCountsByCallerId | keyvalue; track component.key) {
62+
<tr [class.bold]="component.value > 0">
63+
<td>{{ component.key }}</td>
64+
<td>{{ component.value | l10nNumber }}</td>
65+
</tr>
66+
}
67+
</tbody>
68+
</table>
69+
} @else if (tab === 2) {
70+
<h2>Digest cycles: <span id="digest-cycles"></span></h2>
71+
<button type="button" (click)="digestCycles = 0">Reset counter</button>
9872
}
99-
</tbody>
100-
</table>
73+
</div>
74+
</div>
10175
}
10276
</div>

src/SIL.XForge.Scripture/ClientApp/src/app/shared/diagnostic-overlay/diagnostic-overlay.component.scss

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ $table-border-color: #404040;
1515
}
1616

1717
.wrapper:not(.collapsed) {
18-
padding: 4px 12px;
1918
width: 25vw;
2019
min-width: 380px;
2120
}
@@ -66,11 +65,39 @@ h3 {
6665
align-items: center;
6766

6867
h2 {
69-
margin: 0;
68+
margin: 0 0 0 2em;
7069
flex-grow: 1;
7170
}
7271
}
7372

7473
.collapsed .header {
7574
flex-direction: column;
7675
}
76+
77+
.nav-and-content-wrapper {
78+
display: flex;
79+
gap: 8px;
80+
}
81+
82+
.nav-wrapper {
83+
writing-mode: vertical-rl;
84+
display: flex;
85+
86+
> * {
87+
padding: 1em 0.6em;
88+
cursor: pointer;
89+
background-color: #3b3b3f;
90+
91+
&:hover {
92+
background-color: #4f4f53;
93+
}
94+
}
95+
96+
.active {
97+
border-block-start: 2px solid $foreground-color;
98+
}
99+
}
100+
101+
a {
102+
color: $foreground-color;
103+
}

src/SIL.XForge.Scripture/ClientApp/src/app/shared/diagnostic-overlay/diagnostic-overlay.component.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { LocalSettingsService } from 'xforge-common/local-settings.service';
66
import { NoticeService } from 'xforge-common/notice.service';
77
import { RealtimeService } from 'xforge-common/realtime.service';
88
import { UICommonModule } from 'xforge-common/ui-common.module';
9+
import { L10nNumberPipe } from '../../../xforge-common/l10n-number.pipe';
910

1011
export interface DiagnosticOverlayData {
1112
bookNum: number;
@@ -27,12 +28,15 @@ const diagnosticOverlayCollapsedKey = 'DIAGNOSTIC_OVERLAY_COLLAPSED';
2728
export class DiagnosticOverlayComponent {
2829
isExpanded: boolean = true;
2930
isOpen: boolean = true;
31+
tab = 0;
32+
digestCycles = 0;
3033

3134
constructor(
3235
private readonly realtimeService: RealtimeService,
3336
private readonly diagnosticOverlayService: DiagnosticOverlayService,
3437
readonly noticeService: NoticeService,
35-
private readonly localSettings: LocalSettingsService
38+
private readonly localSettings: LocalSettingsService,
39+
private readonly l10nNumber: L10nNumberPipe
3640
) {
3741
if (this.localSettings.get<boolean>(diagnosticOverlayCollapsedKey) === false) {
3842
this.isExpanded = false;
@@ -57,6 +61,13 @@ export class DiagnosticOverlayComponent {
5761
return this.realtimeService.totalDocCount;
5862
}
5963

64+
get digestCycleCounter(): string {
65+
this.digestCycles++;
66+
const displayElement = document.getElementById('digest-cycles');
67+
if (displayElement) displayElement.textContent = this.l10nNumber.transform(this.digestCycles);
68+
return '';
69+
}
70+
6071
toggle(): void {
6172
this.isExpanded = !this.isExpanded;
6273
this.localSettings.set(diagnosticOverlayCollapsedKey, this.isExpanded);

src/SIL.XForge.Scripture/Startup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public class Startup
7373
"join",
7474
"serval-administration",
7575
"system-administration",
76+
"blank-page",
7677
"favicon.ico",
7778
"assets",
7879
];

0 commit comments

Comments
 (0)