1
- import { ComponentProps , DisplayComponent , EventBus , FSComponent , VNode } from "@microsoft/msfs-sdk"
2
- import { CancelToken } from "navigraph/auth"
3
- import { packages } from "../Lib/navigraph"
4
- import { AuthService } from "../Services/AuthService"
5
- import "./InterfaceSample.css"
1
+ import {
2
+ ComponentProps ,
3
+ DisplayComponent ,
4
+ EventBus ,
5
+ FSComponent ,
6
+ MappedSubject ,
7
+ Subject ,
8
+ VNode ,
9
+ } from "@microsoft/msfs-sdk"
6
10
import {
7
11
DownloadProgressPhase ,
8
12
NavigraphEventType ,
9
13
NavigraphNavigationDataInterface ,
10
14
} from "@navigraph/msfs-navigation-data-interface"
15
+ import { NavigationDataStatus } from "@navigraph/msfs-navigation-data-interface/types/meta"
16
+ import { CancelToken } from "navigraph/auth"
17
+ import { packages } from "../Lib/navigraph"
18
+ import { AuthService } from "../Services/AuthService"
11
19
import { Dropdown } from "./Dropdown"
20
+ import { Input } from "./Input"
21
+ import "./InterfaceSample.css"
12
22
13
23
interface InterfaceSampleProps extends ComponentProps {
14
24
bus : EventBus
@@ -21,8 +31,15 @@ export class InterfaceSample extends DisplayComponent<InterfaceSampleProps> {
21
31
private readonly qrCodeRef = FSComponent . createRef < HTMLImageElement > ( )
22
32
private readonly dropdownRef = FSComponent . createRef < Dropdown > ( )
23
33
private readonly downloadButtonRef = FSComponent . createRef < HTMLButtonElement > ( )
24
- private readonly executeButtonRef = FSComponent . createRef < HTMLButtonElement > ( )
25
- private readonly inputRef = FSComponent . createRef < HTMLInputElement > ( )
34
+ private readonly icaoInputRef = FSComponent . createRef < Input > ( )
35
+ private readonly executeIcaoButtonRef = FSComponent . createRef < HTMLButtonElement > ( )
36
+ private readonly sqlInputRef = FSComponent . createRef < Input > ( )
37
+ private readonly executeSqlButtonRef = FSComponent . createRef < HTMLButtonElement > ( )
38
+ private readonly outputRef = FSComponent . createRef < HTMLPreElement > ( )
39
+ private readonly loadingRef = FSComponent . createRef < HTMLDivElement > ( )
40
+ private readonly authContainerRef = FSComponent . createRef < HTMLDivElement > ( )
41
+
42
+ private readonly navigationDataStatus = Subject . create < NavigationDataStatus | null > ( null )
26
43
27
44
private cancelSource = CancelToken . source ( )
28
45
@@ -53,50 +70,123 @@ export class InterfaceSample extends DisplayComponent<InterfaceSampleProps> {
53
70
} )
54
71
}
55
72
56
- public render ( ) : VNode {
73
+ public renderDatabaseStatus ( ) : VNode | void {
57
74
return (
58
- < div class = "auth-container" >
59
- < div class = "horizontal" >
60
- < div class = "vertical" >
61
- < div ref = { this . textRef } > Loading</ div >
62
- < div ref = { this . loginButtonRef } class = "button" />
63
- < div ref = { this . navigationDataTextRef } />
64
- < img ref = { this . qrCodeRef } class = "qr-code" />
75
+ < >
76
+ < div
77
+ class = { MappedSubject . create ( ( [ status ] ) => {
78
+ return status ? "vertical" : "hidden"
79
+ } , this . navigationDataStatus ) }
80
+ >
81
+ < div > { this . navigationDataStatus . map ( s => `Install method: ${ s ?. status } ` ) } </ div >
82
+ < div >
83
+ { this . navigationDataStatus . map (
84
+ s => `Installed format: ${ s ?. installedFormat } revision ${ s ?. installedRevision } ` ,
85
+ ) }
65
86
</ div >
66
- < div class = "vertical" >
67
- < Dropdown ref = { this . dropdownRef } />
68
- < div ref = { this . downloadButtonRef } class = "button" >
69
- Download
87
+ < div > { this . navigationDataStatus . map ( s => `Installed path: ${ s ?. installedPath } ` ) } </ div >
88
+ < div > { this . navigationDataStatus . map ( s => `Installed cycle: ${ s ?. installedCycle } ` ) } </ div >
89
+ < div > { this . navigationDataStatus . map ( s => `Latest cycle: ${ s ?. latestCycle } ` ) } </ div >
90
+ < div > { this . navigationDataStatus . map ( s => `Validity period: ${ s ?. validityPeriod } ` ) } </ div >
91
+ </ div >
92
+ < div class = { this . navigationDataStatus . map ( status => ( status ? "hidden" : "visible" ) ) } > Loading status...</ div >
93
+ </ >
94
+ )
95
+ }
96
+
97
+ public render ( ) : VNode {
98
+ return (
99
+ < >
100
+ < div class = "loading-container" ref = { this . loadingRef } >
101
+ Waiting for navigation data interface to initialize... If building for the first time, this may take a few
102
+ minutes
103
+ </ div >
104
+ < div class = "auth-container" ref = { this . authContainerRef } style = { { display : "none" } } >
105
+ < div class = "horizontal" >
106
+ < div class = "vertical" >
107
+ < h4 > Step 1 - Sign in</ h4 >
108
+ < div ref = { this . textRef } > Loading</ div >
109
+ < div ref = { this . loginButtonRef } class = "button" />
110
+ < div ref = { this . navigationDataTextRef } />
111
+ < img ref = { this . qrCodeRef } class = "qr-code" />
112
+ </ div >
113
+ < div class = "vertical" >
114
+ < h4 > Step 2 - Select Database</ h4 >
115
+ < Dropdown ref = { this . dropdownRef } />
116
+ < div ref = { this . downloadButtonRef } class = "button" >
117
+ Download
118
+ </ div >
119
+ { this . renderDatabaseStatus ( ) }
70
120
</ div >
71
- < input ref = { this . inputRef } type = "text" id = "sql" name = "sql" value = "ESSA" class = "text-field" />
72
- < div ref = { this . executeButtonRef } class = "button" >
73
- Execute SQL
121
+ </ div >
122
+
123
+ < h4 style = "text-align: center;" > Step 3 - Query the database</ h4 >
124
+ < div class = "horizontal" >
125
+ < div class = "vertical" >
126
+ < Input ref = { this . icaoInputRef } value = "TNCM" class = "text-field" />
127
+ < div ref = { this . executeIcaoButtonRef } class = "button" >
128
+ Fetch Airport
129
+ </ div >
130
+ < div style = "height:30px;" > </ div >
131
+ < Input
132
+ ref = { this . sqlInputRef }
133
+ textarea
134
+ value = "SELECT airport_name FROM tbl_airports WHERE airport_identifier = 'TNCM'"
135
+ class = "text-field"
136
+ />
137
+ < div ref = { this . executeSqlButtonRef } class = "button" >
138
+ Execute SQL
139
+ </ div >
74
140
</ div >
141
+ < pre ref = { this . outputRef } id = "output" >
142
+ The output of the query will show up here
143
+ </ pre >
75
144
</ div >
76
145
</ div >
77
- </ div >
146
+ </ >
78
147
)
79
148
}
80
149
81
- public onBeforeRender ( ) : void {
82
- super . onBeforeRender ( )
83
- }
84
-
85
150
public onAfterRender ( node : VNode ) : void {
86
151
super . onAfterRender ( node )
87
152
153
+ // Populate status when ready
154
+ this . navigationDataInterface . onReady ( ( ) => {
155
+ this . navigationDataInterface
156
+ . get_navigation_data_install_status ( )
157
+ . then ( status => this . navigationDataStatus . set ( status ) )
158
+ . catch ( e => console . error ( e ) )
159
+
160
+ // show the auth container
161
+ this . authContainerRef . instance . style . display = "block"
162
+ this . loadingRef . instance . style . display = "none"
163
+ } )
164
+
88
165
this . loginButtonRef . instance . addEventListener ( "click" , ( ) => this . handleClick ( ) )
89
166
this . downloadButtonRef . instance . addEventListener ( "click" , ( ) => this . handleDownloadClick ( ) )
90
167
91
- this . executeButtonRef . instance . addEventListener ( "click" , ( ) => {
168
+ this . executeIcaoButtonRef . instance . addEventListener ( "click" , ( ) => {
92
169
console . time ( "query" )
93
170
this . navigationDataInterface
94
- . get_airport ( this . inputRef . instance . value )
171
+ . get_airport ( this . icaoInputRef . instance . value )
95
172
. then ( airport => {
96
173
console . info ( airport )
97
- console . timeEnd ( "query" )
174
+ this . outputRef . instance . textContent = JSON . stringify ( airport , null , 2 )
98
175
} )
99
176
. catch ( e => console . error ( e ) )
177
+ . finally ( ( ) => console . timeEnd ( "query" ) )
178
+ } )
179
+
180
+ this . executeSqlButtonRef . instance . addEventListener ( "click" , ( ) => {
181
+ console . time ( "query" )
182
+ this . navigationDataInterface
183
+ . execute_sql ( this . sqlInputRef . instance . value , [ ] )
184
+ . then ( result => {
185
+ console . info ( result )
186
+ this . outputRef . instance . textContent = JSON . stringify ( result , null , 2 )
187
+ } )
188
+ . catch ( e => console . error ( e ) )
189
+ . finally ( ( ) => console . timeEnd ( "query" ) )
100
190
} )
101
191
102
192
AuthService . user . sub ( user => {
@@ -105,6 +195,7 @@ export class InterfaceSample extends DisplayComponent<InterfaceSampleProps> {
105
195
this . qrCodeRef . instance . style . display = "none"
106
196
this . loginButtonRef . instance . textContent = "Log out"
107
197
this . textRef . instance . textContent = `Welcome, ${ user . preferred_username } `
198
+ this . displayMessage ( "" )
108
199
109
200
this . handleLogin ( )
110
201
} else {
@@ -120,6 +211,7 @@ export class InterfaceSample extends DisplayComponent<InterfaceSampleProps> {
120
211
await AuthService . signOut ( )
121
212
} else {
122
213
this . cancelSource = CancelToken . source ( ) // Reset any previous cancellations
214
+ this . displayMessage ( "Authenticating.. Scan code (or click it) to sign in" )
123
215
await AuthService . signIn ( p => {
124
216
if ( p ) {
125
217
this . qrCodeRef . instance . src = `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${ p . verification_uri_complete } `
@@ -131,6 +223,7 @@ export class InterfaceSample extends DisplayComponent<InterfaceSampleProps> {
131
223
} , this . cancelSource . token )
132
224
}
133
225
} catch ( err ) {
226
+ this . qrCodeRef . instance . style . display = "none"
134
227
if ( err instanceof Error ) this . displayError ( err . message )
135
228
else this . displayError ( `Unknown error: ${ String ( err ) } ` )
136
229
}
@@ -160,6 +253,13 @@ export class InterfaceSample extends DisplayComponent<InterfaceSampleProps> {
160
253
161
254
// Download navigation data to work dir
162
255
await this . navigationDataInterface . download_navigation_data ( pkg . file . url )
256
+
257
+ // Update navigation data status
258
+ this . navigationDataInterface
259
+ . get_navigation_data_install_status ( )
260
+ . then ( status => this . navigationDataStatus . set ( status ) )
261
+ . catch ( e => console . error ( e ) )
262
+
163
263
this . displayMessage ( "Navigation data downloaded" )
164
264
} catch ( err ) {
165
265
if ( err instanceof Error ) this . displayError ( err . message )
0 commit comments