Skip to content

Commit 75b7164

Browse files
committed
- Added toggle-able log panel to mods-overview page.
- Log panel visibility preferences are serialized. - Added option to open log from `profile-verification-modal`.
1 parent b5e6b49 commit 75b7164

19 files changed

+635
-377
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
@for (logLine of logHistory; track $index) {
3+
<div class="log-line" [attr.level]="logLine.level">
4+
<span class="log-time">{{ logLine.timestamp | date:"mediumTime" }}</span>
5+
<span class="log-level">[{{ logLine.level | titlecase }}]</span>
6+
<span class="log-icon">
7+
@if (logLine.level === "error" || logLine.level === "warn") {
8+
<mat-icon>
9+
{{ logLine.level === "error" ? "cancel" : "warning" }}
10+
</mat-icon>
11+
}
12+
</span>
13+
<span class="log-text">{{ logLine.text }}</span>
14+
</div>
15+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
@use "../../../styles/mixins/" as mixins;
2+
3+
:host {
4+
font-family: monospace;
5+
6+
.log-line {
7+
$text-indent: 1.5rem;
8+
$text-padding: 0.5rem;
9+
10+
padding: $text-padding;
11+
padding-left: $text-indent + $text-padding;
12+
text-indent: -$text-indent;
13+
14+
&:nth-child(odd) {
15+
background-color: rgba(#000, 0.1);
16+
}
17+
18+
&[level="warn"] {
19+
background-color: rgba(#ff0, 0.1);
20+
21+
.log-icon {
22+
color: rgba(#ff0, 0.25);
23+
}
24+
}
25+
26+
&[level="error"] {
27+
background-color: rgba(#f00, 0.1);
28+
29+
.log-icon {
30+
color: rgba(#f00, 0.25);
31+
}
32+
}
33+
34+
.log-level {
35+
font-weight: 600;
36+
font-size: 1.1em;
37+
margin-right: 0.5rem;
38+
}
39+
40+
.log-time {
41+
margin-right: 0.5rem;
42+
opacity: 0.8;
43+
}
44+
45+
.log-icon {
46+
display: inline-flex;
47+
align-items: center;
48+
text-indent: 0;
49+
margin-right: 0.5rem;
50+
position: relative;
51+
top: 0.25rem;
52+
53+
&:empty {
54+
display: none;
55+
}
56+
57+
mat-icon {
58+
@include mixins.mat-icon-size(1.25rem);
59+
}
60+
}
61+
}
62+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import _ from "lodash";
2+
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from "@angular/core";
3+
import { ComponentState, OnDestroy } from "@lithiumjs/angular";
4+
import { Observable } from "rxjs";
5+
import { Hook, LogLevel, LogMessage } from "electron-log";
6+
import { BaseComponent } from "../../core/base-component";
7+
import { log } from "../../util/logger";
8+
9+
interface LogEntry {
10+
level: LogLevel;
11+
text: string;
12+
timestamp: Date
13+
}
14+
15+
@Component({
16+
selector: "app-log",
17+
templateUrl: "./app-log.component.html",
18+
styleUrls: ["./app-log.component.scss"],
19+
changeDetection: ChangeDetectionStrategy.OnPush,
20+
providers: [
21+
ComponentState.create(AppLogComponent),
22+
]
23+
})
24+
export class AppLogComponent extends BaseComponent {
25+
26+
protected readonly logHistory: LogEntry[] = [];
27+
28+
private readonly logHook: Hook = (message: LogMessage): LogMessage => {
29+
this.logHistory.push({
30+
level: message.level,
31+
text: this.formatLogData(message.data),
32+
timestamp: message.date
33+
});
34+
this.cdRef.markForCheck();
35+
return message;
36+
};
37+
38+
@OnDestroy()
39+
private readonly onDestroy$!: Observable<void>;
40+
41+
constructor(private readonly cdRef: ChangeDetectorRef) {
42+
super({ cdRef });
43+
44+
log.hooks.push(this.logHook);
45+
46+
this.onDestroy$.subscribe(() => _.remove<Hook>(log.hooks, this.logHook));
47+
}
48+
49+
private formatLogData(logData?: any[]): string {
50+
return logData?.map(data => typeof data === "object" ? JSON.stringify(data) : data.toString()).join(" ") ?? "";
51+
}
52+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { NgModule } from "@angular/core";
2+
import { CommonModule } from "@angular/common";
3+
import { MatIconModule } from "@angular/material/icon";
4+
import { AppLogComponent } from "./app-log.component";
5+
6+
@NgModule({
7+
declarations: [
8+
AppLogComponent
9+
],
10+
imports: [
11+
CommonModule,
12+
13+
MatIconModule
14+
],
15+
exports: [
16+
AppLogComponent
17+
]
18+
})
19+
export class AppLogComponentModule { }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./app-log.component";
2+
export * from "./app-log.module";

src/app/modals/profile-verification-results/profile-verification-results.modal.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

1515
<span matSnackBarActions>
1616
@if (errors.length > 0) {
17+
@if (!(isLogPanelEnabled$ | async)) {
18+
<button mat-button matSnackBarAction (click)="appManager.toggleLogPanel(); snackBarRef.dismissWithAction()">
19+
Log
20+
</button>
21+
}
22+
1723
<button mat-button matSnackBarAction (click)="snackBarRef.dismissWithAction()">
1824
Close
1925
</button>

src/app/modals/profile-verification-results/profile-verification-results.modal.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject } from "@
22
import { MatButtonModule } from "@angular/material/button";
33
import { MAT_SNACK_BAR_DATA, MatSnackBarModule, MatSnackBarRef } from "@angular/material/snack-bar";
44
import { CommonModule } from "@angular/common";
5+
import { Store } from "@ngxs/store";
6+
import { Observable } from "rxjs";
7+
import { AppState } from "../../state";
58
import { log } from "../../util/logger";
9+
import { LangUtils } from "../../util/lang-utils";
610
import { BaseComponent } from "../../core/base-component";
711
import { AppProfile } from "../../models/app-profile";
8-
import { LangUtils } from "../../util/lang-utils";
12+
import { AppStateBehaviorManager } from "../../services/app-state-behavior-manager";
913

1014
@Component({
1115
templateUrl: "./profile-verification-results.modal.html",
@@ -58,15 +62,20 @@ export class AppProfileVerificationResultsModal extends BaseComponent {
5862

5963
private static readonly BLACKLISTED_ERROR_KEYS: Array<string> = [];
6064

65+
public readonly isLogPanelEnabled$: Observable<boolean>;
66+
6167
protected readonly errors: string[];
6268

6369
constructor(
6470
cdRef: ChangeDetectorRef,
71+
store: Store,
6572
protected readonly snackBarRef: MatSnackBarRef<AppProfileVerificationResultsModal>,
73+
protected readonly appManager: AppStateBehaviorManager,
6674
@Inject(MAT_SNACK_BAR_DATA) verificationResults: AppProfile.VerificationResultRecord<string>
6775
) {
6876
super({ cdRef });
6977

78+
this.isLogPanelEnabled$ = store.select(AppState.isLogPanelEnabled);
7079
this.errors = this.collectErrors(verificationResults);
7180
}
7281

@@ -76,7 +85,7 @@ export class AppProfileVerificationResultsModal extends BaseComponent {
7685
const errorText = this.mapVerificationResultToError(propertyKey, verificationResult);
7786

7887
if (errorText && !errors.includes(errorText)) {
79-
log.error(`Profile verification error:`, propertyKey, errorText, verificationResult);
88+
log.error(`Profile verification error:`, `"${propertyKey}"`, errorText);
8089

8190
if (!logOnly) {
8291
errors.push(errorText);

src/app/models/app-data.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface AppData {
1313
modListColumns?: string[];
1414
deployInProgress?: boolean;
1515
steamCompatDataRoot?: string;
16+
logPanelEnabled?: boolean;
1617
}
1718

1819
export namespace AppData {

src/app/models/app-message.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ export namespace AppMessage {
193193
};
194194
}
195195

196+
export interface ToggleLogPanel extends Base {
197+
id: `${Prefix}:toggleLogPanel`;
198+
}
199+
196200
export interface CheckLinkSupported extends Base {
197201
id: `${Prefix}:checkLinkSupported`;
198202
data: {
@@ -234,6 +238,7 @@ export namespace AppMessage {
234238
| FindBestProfileDefaults
235239
| ShowAboutInfo
236240
| ToggleModListColumn
241+
| ToggleLogPanel
237242
| CheckLinkSupported
238243
| ResolveResourceUrl;
239244

@@ -616,6 +621,7 @@ export namespace AppMessage {
616621
"app:findBestProfileDefaults",
617622
"app:showAboutInfo",
618623
"app:toggleModListColumn",
624+
"app:toggleLogPanel",
619625
"app:checkLinkSupported",
620626
"app:resolveResourceUrl",
621627

src/app/models/app-settings-user-cfg.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ export interface AppSettingsUserCfg {
77
modListColumns?: string[];
88
verifyProfileOnStart: boolean;
99
steamCompatDataRoot?: string;
10+
logPanelEnabled?: boolean;
1011
}

0 commit comments

Comments
 (0)