Skip to content

Commit aa0c8b6

Browse files
authored
Improve error handling (#38)
Improve error handling and making status service more flexible so that it can be used across application
1 parent 81188e7 commit aa0c8b6

File tree

9 files changed

+2715
-567
lines changed

9 files changed

+2715
-567
lines changed

package-lock.json

Lines changed: 2609 additions & 526 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<div>
2+
<app-banner-display class="global-banner"></app-banner-display>
3+
24
<div>
3-
<app-main-sweep
4-
*ngIf="isMainSweepVisible"
5-
[sweepConfig]="sweepConfig"
6-
></app-main-sweep>
5+
<app-main-sweep *ngIf="isMainSweepVisible" [sweepConfig]="sweepConfig"></app-main-sweep>
76
<app-empty-config *ngIf="!isMainSweepVisible"></app-empty-config>
87
</div>
9-
</div>
8+
</div>

script-gen-ui/src/app/app.component.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ import { SweepModel } from './model/sweep_data/sweepModel';
77
import { IpcData } from './model/ipcData';
88
import { MainSweepComponent } from './components/main-sweep/main-sweep.component';
99
import { EmptyConfigComponent } from './components/empty-config/empty-config.component';
10+
import { BannerDisplayComponent } from './components/main-sweep/banner-display/banner-display.component';
1011
import { CommonModule } from '@angular/common';
1112
import { FormsModule } from '@angular/forms';
1213
import { MatIconModule } from '@angular/material/icon';
1314
import { BrowserModule } from '@angular/platform-browser';
15+
import { StatusService } from './services/status.service';
16+
import { StatusMsg } from './model/sweep_data/statusMsg';
17+
import { StatusType } from './model/interface';
1418

1519

1620
declare const acquireVsCodeApi: unknown;
@@ -27,7 +31,8 @@ const vscode = typeof acquireVsCodeApi === 'function' ? acquireVsCodeApi() : { p
2731
MatIconModule,
2832
MainSweepComponent,
2933
EmptyConfigComponent,
30-
],
34+
BannerDisplayComponent
35+
],
3136
templateUrl: './app.component.html',
3237
styleUrl: './app.component.scss',
3338
})
@@ -39,7 +44,7 @@ export class AppComponent implements OnInit, OnDestroy {
3944
sweepConfig: SweepConfig | undefined;
4045
isMainSweepVisible = false;
4146

42-
constructor(private webSocketService: WebSocketService) {}
47+
constructor(private webSocketService: WebSocketService, private statusService: StatusService) {}
4348

4449
ngOnInit() {
4550
this.webSocketService.connect();
@@ -58,6 +63,7 @@ export class AppComponent implements OnInit, OnDestroy {
5863
}
5964

6065
processServerData(message: string): void {
66+
this.statusService.show(new StatusMsg({ message: "Loading data...", status_type: StatusType.Info, time_stamp: Date.now().toString() }))
6167
try {
6268
// Parse the message as an IpcData object
6369
const ipcData: IpcData = JSON.parse(message);
@@ -67,7 +73,9 @@ export class AppComponent implements OnInit, OnDestroy {
6773
ipcData.request_type === 'initial_response' ||
6874
ipcData.request_type === 'evaluated_response' ||
6975
ipcData.request_type === 'reset_response'
70-
) {
76+
)
77+
{
78+
vscode.postMessage({ command: 'update_session' , payload: message});
7179
// Parse the json_value as the SweepModel
7280
const data = JSON.parse(ipcData.json_value);
7381
if (data.sweep_model) {
@@ -77,7 +85,7 @@ export class AppComponent implements OnInit, OnDestroy {
7785
// Update visibility based on the device list
7886
if (this.sweepConfig.device_list.length > 0) {
7987
this.isMainSweepVisible = true;
80-
vscode.postMessage({ command: 'update_session' , payload: message});
88+
8189
}
8290
} else {
8391
console.error('sweep_model property is missing in the data');
@@ -97,6 +105,7 @@ export class AppComponent implements OnInit, OnDestroy {
97105
} catch (error) {
98106
console.log('Error parsing server data:', error);
99107
}
108+
this.statusService.clear()
100109
}
101110

102111
ngOnDestroy(): void {
Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { CommonModule } from '@angular/common';
2-
import { Component, Input } from '@angular/core';
2+
import { Component, Input, OnInit, OnDestroy, Inject, ChangeDetectorRef } from '@angular/core';
33
import { FormsModule } from '@angular/forms';
44
import { MatIconModule } from '@angular/material/icon';
55
import { BrowserModule } from '@angular/platform-browser';
66
import { StatusMsg } from '../../../model/sweep_data/statusMsg';
7+
import { StatusService } from '../../../services/status.service';
8+
import { Subscription } from 'rxjs';
79

810
@Component({
911
selector: 'app-banner-display',
@@ -12,6 +14,43 @@ import { StatusMsg } from '../../../model/sweep_data/statusMsg';
1214
templateUrl: './banner-display.component.html',
1315
styleUrl: './banner-display.component.scss',
1416
})
15-
export class BannerDisplayComponent {
16-
@Input() statusMsg: StatusMsg | undefined;
17+
export class BannerDisplayComponent implements OnInit, OnDestroy {
18+
private _external?: StatusMsg;
19+
private _service?: StatusMsg;
20+
private _displayed?: StatusMsg;
21+
private _sub?: Subscription;
22+
23+
@Input()
24+
set statusMsg(value: StatusMsg | undefined) {
25+
this._external = value;
26+
this.updateDisplayed();
27+
}
28+
get statusMsg(): StatusMsg | undefined {
29+
return this._displayed;
30+
}
31+
32+
constructor(
33+
@Inject(StatusService) private statusService: StatusService,
34+
private cdr: ChangeDetectorRef
35+
) {}
36+
37+
ngOnInit(): void {
38+
this._sub = this.statusService.status$.subscribe((msg: StatusMsg | undefined) => {
39+
this._service = msg;
40+
this.updateDisplayed();
41+
this.cdr.detectChanges(); // Trigger change detection
42+
});
43+
}
44+
45+
ngOnDestroy(): void {
46+
this._sub?.unsubscribe();
47+
}
48+
49+
clearServiceMessage(): void {
50+
this.statusService.clear();
51+
}
52+
53+
private updateDisplayed(): void {
54+
this._displayed = this._external ?? this._service;
55+
}
1756
}

script-gen-ui/src/app/components/main-sweep/main-sweep.component.html

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
<div *ngIf="statusMsg">
2-
<app-banner-display
3-
[statusMsg]="statusMsg"
4-
class="banner-display"
5-
></app-banner-display>
6-
</div>
71
<div class="parent-container">
82
<div
93
class="input-container"

script-gen-ui/src/app/components/main-sweep/main-sweep.component.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ import { BrowserModule } from '@angular/platform-browser';
3535
import { PlotContainerComponent } from './plot-container/plot-container.component';
3636
import { InputNumericComponent } from '../controls/input-numeric/input-numeric.component';
3737
import { ListComponent } from './list/list.component';
38-
import { BannerDisplayComponent } from './banner-display/banner-display.component';
39-
import { StatusMsg } from '../../model/sweep_data/statusMsg';
4038
import { TooltipComponent } from './tooltip/tooltip.component';
39+
import { StatusService } from '../../services/status.service';
4140

4241
@Component({
4342
selector: 'app-main-sweep',
@@ -54,9 +53,8 @@ import { TooltipComponent } from './tooltip/tooltip.component';
5453
TimingComponent,
5554
PlotContainerComponent,
5655
ListComponent,
57-
BannerDisplayComponent,
5856
TooltipComponent
59-
],
57+
],
6058
templateUrl: './main-sweep.component.html',
6159
styleUrls: ['./main-sweep.component.scss'],
6260
})
@@ -137,10 +135,8 @@ export class MainSweepComponent implements OnChanges {
137135
isStepExpanded = false;
138136
isSweepExpanded = false;
139137
channelsExpanderState: Map<string, boolean> = new Map<string, boolean>();
140-
statusMsg: StatusMsg | undefined;
141-
private statusMsgTimeout: number | undefined;
142138

143-
constructor(private webSocketService: WebSocketService) {}
139+
constructor(private webSocketService: WebSocketService, private statusService: StatusService) {}
144140

145141
// ngOnInit() {
146142
// this.updateSweepListsWithNames();
@@ -322,16 +318,7 @@ export class MainSweepComponent implements OnChanges {
322318

323319
updateStatusMsg() {
324320
if (this.sweepConfig && this.sweepConfig.status_msg) {
325-
this.statusMsg = this.sweepConfig.status_msg;
326-
327-
// Clear any previous timeout
328-
if (this.statusMsgTimeout !== undefined) {
329-
window.clearTimeout(this.statusMsgTimeout);
330-
}
331-
// Set a new timeout to clear the statusMsg after 5 seconds
332-
this.statusMsgTimeout = window.setTimeout(() => {
333-
this.statusMsg = undefined;
334-
}, 5000);
321+
this.statusService.showTemporary(this.sweepConfig.status_msg, 5000);
335322
}
336323
}
337324

script-gen-ui/src/app/model/interface.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ export interface IDevice {
113113
}
114114

115115
export enum StatusType {
116-
Info,
117-
Warning,
118-
Error,
116+
Info = "Info",
117+
Warning = "Warning",
118+
Error = "Error",
119119
}
120120

121121
export interface IStatusMsg {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Injectable } from '@angular/core';
2+
import { BehaviorSubject, Observable } from 'rxjs';
3+
import { StatusMsg } from '../model/sweep_data/statusMsg';
4+
5+
@Injectable({ providedIn: 'root' })
6+
export class StatusService {
7+
private readonly _status = new BehaviorSubject<StatusMsg | undefined>(undefined);
8+
readonly status$: Observable<StatusMsg | undefined> = this._status.asObservable();
9+
10+
show(msg: StatusMsg | undefined): void {
11+
this._status.next(msg);
12+
}
13+
14+
showTemporary(msg: StatusMsg, timeoutMs = 5000): void {
15+
this.show(msg);
16+
if (timeoutMs > 0) {
17+
setTimeout(() => {
18+
// Only clear if the message is still the same instance
19+
if (this._status.getValue() === msg) {
20+
this.clear();
21+
}
22+
}, timeoutMs);
23+
}
24+
}
25+
26+
clear(): void {
27+
this._status.next(undefined);
28+
}
29+
}

script-gen-ui/src/app/websocket.service.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { Injectable } from '@angular/core';
22
import { Observable, Subject } from 'rxjs';
33
import { IpcData } from './model/ipcData';
44
import { v4 as uuidv4 } from 'uuid';
5+
import { StatusMsg } from './model/sweep_data/statusMsg';
6+
import { StatusType } from './model/interface';
7+
import { StatusService } from './services/status.service';
58

69
@Injectable({
710
providedIn: 'root',
@@ -10,8 +13,7 @@ export class WebSocketService {
1013
private socket: WebSocket;
1114
private messageSubject: Subject<string> = new Subject<string>();
1215
private readonly CHUNK_SIZE = 30 * 1024; // 30 KB per chunk
13-
14-
constructor() {
16+
constructor(private statusService: StatusService) {
1517
this.socket = new WebSocket('ws://localhost:27950/ws');
1618
}
1719

@@ -80,8 +82,14 @@ export class WebSocketService {
8082
'WebSocket is not open. ReadyState:',
8183
this.socket.readyState
8284
);
83-
}
85+
const msg = new StatusMsg({
86+
message: "WebSocket connection failed. Please close and relaunch the TSP Script Generation webView UI",
87+
status_type: StatusType.Error,
88+
time_stamp: Date.now().toString()
89+
});
90+
this.statusService.show(msg);
8491
}
92+
}
8593

8694
getMessages(): Observable<string> {
8795
return this.messageSubject.asObservable();

0 commit comments

Comments
 (0)