Skip to content

Commit 58175ea

Browse files
committed
feat: better js interface, better(?) wasm error handling
1 parent ae18442 commit 58175ea

File tree

10 files changed

+235
-45
lines changed

10 files changed

+235
-45
lines changed

.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
{
2-
"eslint.workingDirectories": ["Sources/Code/TypeScript"]
2+
"eslint.workingDirectories": ["Sources/Code/TypeScript"],
3+
"editor.codeActionsOnSave": {
4+
"source.fixAll.eslint": true,
5+
6+
}
37
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* Dropdown container */
2+
.dropdown {
3+
position: relative;
4+
display: inline-block;
5+
width: 300px;
6+
text-align: center;
7+
}
8+
9+
/* Dropdown button */
10+
.dropdown-toggle {
11+
background: white;
12+
color: black;
13+
padding: 10px;
14+
width: 100%;
15+
}
16+
17+
/* Dropdown menu */
18+
.dropdown-menu {
19+
display: none;
20+
position: absolute;
21+
background: white;
22+
color: black;
23+
list-style: none;
24+
padding: 0;
25+
margin: 0;
26+
width: 100%;
27+
}
28+
29+
.dropdown-menu li {
30+
padding: 10px;
31+
width: 100%;
32+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { ComponentProps, ComputedSubject, DisplayComponent, FSComponent, Subject, VNode } from "@microsoft/msfs-sdk"
2+
import "./Dropdown.css"
3+
4+
export class Dropdown extends DisplayComponent<ComponentProps> {
5+
private readonly dropdownButtonRef = FSComponent.createRef<HTMLDivElement>()
6+
private readonly dropdownMenuRef = FSComponent.createRef<HTMLUListElement>()
7+
8+
private readonly dropdownButtonText = Subject.create<string>("Select an item")
9+
10+
private navdataFormat: null | string = null
11+
12+
public render(): VNode {
13+
return (
14+
<div class="dropdown">
15+
<div ref={this.dropdownButtonRef} class="dropdown-toggle">
16+
{this.dropdownButtonText}
17+
</div>
18+
<ul ref={this.dropdownMenuRef} class="dropdown-menu" />
19+
</div>
20+
)
21+
}
22+
23+
public onAfterRender(node: VNode): void {
24+
const dropdownButton = this.dropdownButtonRef.instance
25+
const dropdownMenu = this.dropdownMenuRef.instance
26+
27+
dropdownButton.addEventListener("click", function () {
28+
dropdownMenu.style.display = dropdownMenu.style.display === "block" ? "none" : "block"
29+
})
30+
31+
// Close the dropdown when clicking outside of it
32+
document.addEventListener("click", this.onDropdownItemClick.bind(this))
33+
}
34+
35+
public onDropdownItemClick(event: Event): void {
36+
const dropdownButton = this.dropdownButtonRef.instance
37+
const dropdownMenu = this.dropdownMenuRef.instance
38+
39+
const target = event.target as HTMLElement
40+
if (!target) {
41+
return
42+
}
43+
if (!dropdownMenu.contains(target) && !dropdownButton.contains(target)) {
44+
dropdownMenu.style.display = "none"
45+
} else if (dropdownMenu.contains(target)) {
46+
this.dropdownButtonText.set(target.textContent as string)
47+
const navdataFormat = target.dataset.navdataFormat
48+
if (navdataFormat) {
49+
this.navdataFormat = navdataFormat
50+
}
51+
}
52+
}
53+
54+
public addDropdownItem(text: string, format: string): void {
55+
const dropdownItem = document.createElement("li")
56+
dropdownItem.textContent = text
57+
dropdownItem.dataset.navdataFormat = format
58+
this.dropdownMenuRef.instance.appendChild(dropdownItem)
59+
}
60+
61+
public getNavdataFormat(): string | null {
62+
return this.navdataFormat
63+
}
64+
}

Sources/Code/TypeScript/Components/NavigraphLogin.css

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
font-size: x-large;
33
width: 100%;
44
height: 100%;
5-
display: flex;
6-
align-items: center;
7-
justify-content: center;
8-
flex-direction: column;
5+
position: relative;
6+
top: 100px;
97
}
108

11-
.login-button {
12-
width: 200px;
13-
height: 100px;
9+
.button {
10+
width: 150px;
11+
height: 50px;
1412
font-size: x-large;
1513
margin-top: 5px;
1614
background: white;
@@ -25,3 +23,17 @@
2523
height: 300px;
2624
display: none;
2725
}
26+
27+
.horizontal {
28+
display: flex;
29+
flex-direction: row;
30+
justify-content: center;
31+
align-items: center;
32+
}
33+
34+
.vertical {
35+
display: flex;
36+
flex-direction: column;
37+
justify-content: center;
38+
align-items: center;
39+
}

Sources/Code/TypeScript/Components/NavigraphLogin.tsx

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { ComponentProps, DisplayComponent, EventBus, FSComponent, VNode } from "@microsoft/msfs-sdk";
2-
import { getDefaultAppDomain } from "@navigraph/app";
3-
import { CancelToken, navigraphRequest } from "navigraph/auth";
4-
import { AuthService } from "../Services/AuthService";
5-
import "./NavigraphLogin.css";
6-
1+
import { ComponentProps, DisplayComponent, EventBus, FSComponent, VNode } from "@microsoft/msfs-sdk"
2+
import { CancelToken, navigraphRequest } from "navigraph/auth"
3+
import { packages } from "../Lib/navigraph"
4+
import { AuthService } from "../Services/AuthService"
5+
import "./NavigraphLogin.css"
6+
import { Dropdown } from "./Dropdown"
77

88
interface NavigraphLoginProps extends ComponentProps {
99
bus: EventBus
@@ -12,8 +12,10 @@ interface NavigraphLoginProps extends ComponentProps {
1212
export class NavigraphLogin extends DisplayComponent<NavigraphLoginProps> {
1313
private readonly textRef = FSComponent.createRef<HTMLDivElement>()
1414
private readonly navdataTextRef = FSComponent.createRef<HTMLDivElement>()
15-
private readonly buttonRef = FSComponent.createRef<HTMLButtonElement>()
15+
private readonly loginButtonRef = FSComponent.createRef<HTMLButtonElement>()
1616
private readonly qrCodeRef = FSComponent.createRef<HTMLImageElement>()
17+
private readonly dropdownRef = FSComponent.createRef<Dropdown>()
18+
private readonly downloadButtonRef = FSComponent.createRef<HTMLButtonElement>()
1719

1820
private cancelSource = CancelToken.source()
1921

@@ -42,10 +44,20 @@ export class NavigraphLogin extends DisplayComponent<NavigraphLoginProps> {
4244
public render(): VNode {
4345
return (
4446
<div class="auth-container">
45-
<div ref={this.textRef} />
46-
<div ref={this.buttonRef} onClick={this.handleClick.bind(this)} class="login-button" />
47-
<div ref={this.navdataTextRef} />
48-
<img ref={this.qrCodeRef} class="qr-code" />
47+
<div class="horizontal">
48+
<div class="vertical">
49+
<div ref={this.textRef} />
50+
<div ref={this.loginButtonRef} class="button" />
51+
<div ref={this.navdataTextRef} />
52+
<img ref={this.qrCodeRef} class="qr-code" />
53+
</div>
54+
<div class="vertical">
55+
<Dropdown ref={this.dropdownRef} />
56+
<div ref={this.downloadButtonRef} class="button">
57+
Download
58+
</div>
59+
</div>
60+
</div>
4961
</div>
5062
)
5163
}
@@ -57,18 +69,19 @@ export class NavigraphLogin extends DisplayComponent<NavigraphLoginProps> {
5769
public onAfterRender(node: VNode): void {
5870
super.onAfterRender(node)
5971

60-
this.buttonRef.instance.addEventListener("click", () => this.handleClick().catch(e => console.error(e)))
72+
this.loginButtonRef.instance.addEventListener("click", () => this.handleClick().catch(e => console.error(e)))
73+
this.downloadButtonRef.instance.addEventListener("click", () => this.handleDownloadClick())
6174

6275
AuthService.user.sub(user => {
6376
if (user) {
6477
this.qrCodeRef.instance.src = ""
6578
this.qrCodeRef.instance.style.display = "none"
66-
this.buttonRef.instance.textContent = "Log out"
79+
this.loginButtonRef.instance.textContent = "Log out"
6780
this.textRef.instance.textContent = `Welcome, ${user.preferred_username}`
6881

69-
this.handleLogin().catch(e => console.error(e))
82+
this.handleLogin()
7083
} else {
71-
this.buttonRef.instance.textContent = "Sign in"
84+
this.loginButtonRef.instance.textContent = "Sign in"
7285
this.textRef.instance.textContent = "Not signed in"
7386
}
7487
}, true)
@@ -81,25 +94,42 @@ export class NavigraphLogin extends DisplayComponent<NavigraphLoginProps> {
8194
this.cancelSource = CancelToken.source() // Reset any previous cancellations
8295
AuthService.signIn(p => {
8396
if (p) {
84-
this.qrCodeRef.instance.src = `https://api.qrserver.com/v1/create-qr-code/?size=500x500&data=${p.verification_uri_complete}`
97+
this.qrCodeRef.instance.src = `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${p.verification_uri_complete}`
8598
this.qrCodeRef.instance.style.display = "block"
8699
console.info(p.verification_uri_complete)
87100
}
88101
}, this.cancelSource.token).catch(e => console.error("Failed to sign in!", e))
89102
}
90103
}
91104

92-
private async handleLogin() {
93-
console.log("successful login, downloading navdata")
94-
this.navdataTextRef.instance.textContent = "Downloading navdata..."
95-
// leaving this here for now (messy) until the PR from the sdk is merged
96-
const result = await navigraphRequest
97-
.get(`https://fmsdata.api.${getDefaultAppDomain()}/v3/packages?format=avionics_v1`)
105+
private handleLogin() {
106+
// Let's display all of our packages
107+
packages
108+
.listPackages()
109+
.then(pkgs => {
110+
for (const pkg of pkgs) {
111+
this.dropdownRef.instance.addDropdownItem(pkg.format, pkg.format)
112+
}
113+
})
114+
.catch(e => console.error(e))
115+
}
116+
117+
private handleDownloadClick() {
118+
packages
119+
.getPackage(this.dropdownRef.instance.getNavdataFormat() as string)
120+
.then(pkg => {
121+
const url = pkg.file.url
122+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
123+
this.commBusListener.call(
124+
"COMM_BUS_WASM_CALLBACK",
125+
"NAVIGRAPH_DownloadNavdata",
126+
JSON.stringify({
127+
url,
128+
folder: pkg.format,
129+
}),
130+
)
131+
this.navdataTextRef.instance.textContent = "Downloading navdata..."
132+
})
98133
.catch(e => console.error(e))
99-
const signedUrl = result.data[0].files[0].signed_url
100-
console.log("signed url", signedUrl)
101-
await this.commBusListener.call("COMM_BUS_WASM_CALLBACK", "NAVIGRAPH_DownloadNavdata", JSON.stringify({
102-
url: signedUrl
103-
}))
104134
}
105-
}
135+
}

Sources/Code/TypeScript/lib/navigraph.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { DataStore } from "@microsoft/msfs-sdk"
22
import { initializeApp, NavigraphApp, Scope } from "@navigraph/app"
33
import { getAuth } from "@navigraph/auth"
4+
import { getPackagesAPI } from "@navigraph/packages"
45
import { getChartsAPI } from "@navigraph/charts"
56

67
const config: NavigraphApp = {
@@ -32,3 +33,5 @@ export const auth = getAuth({
3233
})
3334

3435
export const charts = getChartsAPI()
36+
37+
export const packages = getPackagesAPI()

Sources/Code/TypeScript/rollup.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import copy from "rollup-plugin-copy"
33
import esbuild from "rollup-plugin-esbuild"
44
import css from "rollup-plugin-import-css"
55

6-
let DEBUG = false
6+
let DEBUG = true
77

88
let outputDest = "../../../PackageSources"
99
if (DEBUG) {

Sources/Code/WASM/navdata_updater/src/dispatcher.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,23 @@ impl<'a> Dispatcher<'a> {
3636

3737
fn handle_initialized(&mut self) {
3838
CommBus::call("NAVIGRAPH_Initialized", "", CommBusBroadcastFlags::All);
39-
let captured_downloader = self.downloader.clone();
40-
self.commbus.register("NAVIGRAPH_DownloadNavdata", move |args| {
41-
captured_downloader.download(args)
42-
}).expect("Failed to register NAVIGRAPH_DownloadNavdata");
39+
{
40+
let captured_downloader = self.downloader.clone();
41+
self.commbus
42+
.register("NAVIGRAPH_DownloadNavdata", move |args| {
43+
captured_downloader.download(args)
44+
})
45+
.expect("Failed to register NAVIGRAPH_DownloadNavdata");
46+
}
47+
// Left out for now as the sim doesn't seem to like deleting files (?)
48+
// {
49+
// let captured_downloader = self.downloader.clone();
50+
// self.commbus
51+
// .register("NAVIGRAPH_DeleteAllFiles", move |_| {
52+
// captured_downloader.delete_all_files()
53+
// })
54+
// .expect("Failed to register NAVIGRAPH_DeleteAllFiles");
55+
// }
4356
}
4457

4558
fn handle_update(&mut self) {

0 commit comments

Comments
 (0)