From 5ab1acaf64d9251e489ac013f44737cc41121f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 11:10:47 +0200 Subject: [PATCH 01/17] fix: always stop console timer --- examples/gauge/Components/InterfaceSample.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 67de4a8..4a64e0b 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -78,10 +78,6 @@ export class InterfaceSample extends DisplayComponent { ) } - public onBeforeRender(): void { - super.onBeforeRender() - } - public onAfterRender(node: VNode): void { super.onAfterRender(node) @@ -92,11 +88,9 @@ export class InterfaceSample extends DisplayComponent { console.time("query") this.navigationDataInterface .get_airport(this.inputRef.instance.value) - .then(airport => { - console.info(airport) - console.timeEnd("query") - }) + .then(airport => console.info(airport)) .catch(e => console.error(e)) + .finally(() => console.timeEnd("query")) }) AuthService.user.sub(user => { From 3104d52b48e575d50398751ab3d8eca038a6e21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 11:30:52 +0200 Subject: [PATCH 02/17] chore: execute SQL -> fetch airport Since you can't actually input SQL --- examples/gauge/Components/InterfaceSample.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 4a64e0b..4678224 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -70,7 +70,7 @@ export class InterfaceSample extends DisplayComponent {
- Execute SQL + Fetch Airport
From 3a8e7335bb76050912440f6a76ea3b7337d8843a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 12:13:58 +0200 Subject: [PATCH 03/17] feat: channel key inputs to input when focused --- examples/gauge/Components/Input.tsx | 51 +++++++++++++++++++ examples/gauge/Components/InterfaceSample.tsx | 5 +- examples/gauge/global.d.ts | 15 ++++++ 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 examples/gauge/Components/Input.tsx create mode 100644 examples/gauge/global.d.ts diff --git a/examples/gauge/Components/Input.tsx b/examples/gauge/Components/Input.tsx new file mode 100644 index 0000000..fb42460 --- /dev/null +++ b/examples/gauge/Components/Input.tsx @@ -0,0 +1,51 @@ +import { ComponentProps, DisplayComponent, FSComponent, Subscribable, UUID, VNode } from "@microsoft/msfs-sdk" + +interface InputProps extends ComponentProps { + type: HTMLInputElement["type"] + name?: string + value?: string + class?: string | Subscribable +} + +export class Input extends DisplayComponent { + private readonly inputId = UUID.GenerateUuid() + private readonly inputRef = FSComponent.createRef() + + get value() { + return this.inputRef.instance.value + } + + onAfterRender(node: VNode): void { + super.onAfterRender(node) + + this.inputRef.instance.onfocus = this.onInputFocus + this.inputRef.instance.onblur = this.onInputBlur + } + + private getInputProps() { + return { name: this.props.name, value: this.props.value, class: this.props.class } + } + + /** + * Method to handle when input focus is set + * @param e The focus event. + */ + private onInputFocus = (e: FocusEvent): void => { + e.preventDefault() + + Coherent.trigger("FOCUS_INPUT_FIELD", this.inputId, "", "", this.inputRef.instance.value, false) + Coherent.on("mousePressOutsideView", () => this.inputRef.instance.blur()) + } + + /** + * Method to handle on input blur + */ + private onInputBlur = (): void => { + Coherent.trigger("UNFOCUS_INPUT_FIELD", "") + Coherent.off("mousePressOutsideView") + } + + render() { + return + } +} diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 4678224..a955ce6 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -9,6 +9,7 @@ import { NavigraphNavigationDataInterface, } from "@navigraph/msfs-navigation-data-interface" import { Dropdown } from "./Dropdown" +import { Input } from "./Input" interface InterfaceSampleProps extends ComponentProps { bus: EventBus @@ -22,7 +23,7 @@ export class InterfaceSample extends DisplayComponent { private readonly dropdownRef = FSComponent.createRef() private readonly downloadButtonRef = FSComponent.createRef() private readonly executeButtonRef = FSComponent.createRef() - private readonly inputRef = FSComponent.createRef() + private readonly inputRef = FSComponent.createRef() private cancelSource = CancelToken.source() @@ -68,7 +69,7 @@ export class InterfaceSample extends DisplayComponent {
Download
- +
Fetch Airport
diff --git a/examples/gauge/global.d.ts b/examples/gauge/global.d.ts new file mode 100644 index 0000000..2d5dd30 --- /dev/null +++ b/examples/gauge/global.d.ts @@ -0,0 +1,15 @@ +interface CoherentEngine { + /** + * Asynchronously call a C++ handler and retrieve the result + * @param name name of the C++ handler to be called + * @param args any extra parameters to be passed to the C++ handler + * @return promise for the result of the C++ function + */ + call(name: "PLAY_INSTRUMENT_SOUND", soundName: string): Promise + call(name: string, ...args: unknown[]): Promise + + on(name: "SetInputTextFromOS" | "mousePressOutsideView", cb: () => void): void + off(name: "SetInputTextFromOS" | "mousePressOutsideView", cb?: () => void): void + + trigger(name: "FOCUS_INPUT_FIELD" | "UNFOCUS_INPUT_FIELD", ...args: unknown[]) +} From fdd65eb366dff142f91d6a8c2249f8c089b23cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 12:51:59 +0200 Subject: [PATCH 04/17] refactor: improve layout --- examples/gauge/Components/InterfaceSample.css | 27 +++++++++++++++---- examples/gauge/Components/InterfaceSample.tsx | 21 ++++++++++++++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/examples/gauge/Components/InterfaceSample.css b/examples/gauge/Components/InterfaceSample.css index 5ec8e0a..1807453 100644 --- a/examples/gauge/Components/InterfaceSample.css +++ b/examples/gauge/Components/InterfaceSample.css @@ -3,7 +3,6 @@ width: 100%; height: 100%; position: relative; - top: 100px; } .button { @@ -19,16 +18,21 @@ } .qr-code { - width: 300px; - height: 300px; + margin-top: 10px; + width: 250px; + height: 250px; display: none; + background: white; + padding: 10px; + border-radius: 5px; } .horizontal { display: flex; flex-direction: row; - justify-content: center; - align-items: center; + justify-content: space-evenly; + align-items: flex-start; + padding: 2rem; } .vertical { @@ -49,3 +53,16 @@ justify-content: center; align-items: center; } + +pre { + background: #272727; + border-radius: 6px; + padding: 10px; + + min-width: 300px; + min-height: 200px; +} + +h4 { + margin-bottom: 15px; +} diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index a955ce6..13f658d 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -24,6 +24,7 @@ export class InterfaceSample extends DisplayComponent { private readonly downloadButtonRef = FSComponent.createRef() private readonly executeButtonRef = FSComponent.createRef() private readonly inputRef = FSComponent.createRef() + private readonly outputRef = FSComponent.createRef() private cancelSource = CancelToken.source() @@ -59,21 +60,32 @@ export class InterfaceSample extends DisplayComponent {
+

Step 1 - Sign in

Loading
+

Step 2 - Select Database

Download
+
+
+ +

Step 3 - Query the database

+
+
Fetch Airport
+
+            The output of the query will show up here
+          
) @@ -89,7 +101,11 @@ export class InterfaceSample extends DisplayComponent { console.time("query") this.navigationDataInterface .get_airport(this.inputRef.instance.value) - .then(airport => console.info(airport)) + .then(airport => { + console.info(airport) + + this.outputRef.instance.textContent = JSON.stringify(airport, null, 2) + }) .catch(e => console.error(e)) .finally(() => console.timeEnd("query")) }) @@ -100,6 +116,7 @@ export class InterfaceSample extends DisplayComponent { this.qrCodeRef.instance.style.display = "none" this.loginButtonRef.instance.textContent = "Log out" this.textRef.instance.textContent = `Welcome, ${user.preferred_username}` + this.displayMessage("") this.handleLogin() } else { @@ -115,6 +132,7 @@ export class InterfaceSample extends DisplayComponent { await AuthService.signOut() } else { this.cancelSource = CancelToken.source() // Reset any previous cancellations + this.displayMessage("Authenticating.. Scan code (or click it) to sign in") await AuthService.signIn(p => { if (p) { this.qrCodeRef.instance.src = `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${p.verification_uri_complete}` @@ -126,6 +144,7 @@ export class InterfaceSample extends DisplayComponent { }, this.cancelSource.token) } } catch (err) { + this.qrCodeRef.instance.style.display = "none" if (err instanceof Error) this.displayError(err.message) else this.displayError(`Unknown error: ${String(err)}`) } From d8635e8cac3b3b7e7df7c74148ea82c5f73b6779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 14:01:27 +0200 Subject: [PATCH 05/17] feat: support raw SQL input --- examples/gauge/Components/Input.tsx | 11 ++++-- examples/gauge/Components/InterfaceSample.tsx | 37 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/examples/gauge/Components/Input.tsx b/examples/gauge/Components/Input.tsx index fb42460..a94c24a 100644 --- a/examples/gauge/Components/Input.tsx +++ b/examples/gauge/Components/Input.tsx @@ -1,10 +1,9 @@ import { ComponentProps, DisplayComponent, FSComponent, Subscribable, UUID, VNode } from "@microsoft/msfs-sdk" interface InputProps extends ComponentProps { - type: HTMLInputElement["type"] - name?: string value?: string class?: string | Subscribable + textarea?: boolean } export class Input extends DisplayComponent { @@ -23,7 +22,7 @@ export class Input extends DisplayComponent { } private getInputProps() { - return { name: this.props.name, value: this.props.value, class: this.props.class } + return { value: this.props.value, class: this.props.class } } /** @@ -46,6 +45,12 @@ export class Input extends DisplayComponent { } render() { + if (this.props.textarea) + return ( + + ) return } } diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 13f658d..344a760 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -22,8 +22,10 @@ export class InterfaceSample extends DisplayComponent { private readonly qrCodeRef = FSComponent.createRef() private readonly dropdownRef = FSComponent.createRef() private readonly downloadButtonRef = FSComponent.createRef() - private readonly executeButtonRef = FSComponent.createRef() - private readonly inputRef = FSComponent.createRef() + private readonly icaoInputRef = FSComponent.createRef() + private readonly executeIcaoButtonRef = FSComponent.createRef() + private readonly sqlInputRef = FSComponent.createRef() + private readonly executeSqlButtonRef = FSComponent.createRef() private readonly outputRef = FSComponent.createRef() private cancelSource = CancelToken.source() @@ -78,10 +80,20 @@ export class InterfaceSample extends DisplayComponent {

Step 3 - Query the database

- -
+ +
Fetch Airport
+
+ +
+ Execute SQL +
             The output of the query will show up here
@@ -97,19 +109,30 @@ export class InterfaceSample extends DisplayComponent {
     this.loginButtonRef.instance.addEventListener("click", () => this.handleClick())
     this.downloadButtonRef.instance.addEventListener("click", () => this.handleDownloadClick())
 
-    this.executeButtonRef.instance.addEventListener("click", () => {
+    this.executeIcaoButtonRef.instance.addEventListener("click", () => {
       console.time("query")
       this.navigationDataInterface
-        .get_airport(this.inputRef.instance.value)
+        .get_airport(this.icaoInputRef.instance.value)
         .then(airport => {
           console.info(airport)
-
           this.outputRef.instance.textContent = JSON.stringify(airport, null, 2)
         })
         .catch(e => console.error(e))
         .finally(() => console.timeEnd("query"))
     })
 
+    this.executeSqlButtonRef.instance.addEventListener("click", () => {
+      console.time("query")
+      this.navigationDataInterface
+        .execute_sql(this.sqlInputRef.instance.value, [])
+        .then(result => {
+          console.info(result)
+          this.outputRef.instance.textContent = JSON.stringify(result, null, 2)
+        })
+        .catch(e => console.error(e))
+        .finally(() => console.timeEnd("query"))
+    })
+
     AuthService.user.sub(user => {
       if (user) {
         this.qrCodeRef.instance.src = ""

From 4f87955d6ad1d85263026bc9b8e76e7ad8dac2e7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= 
Date: Fri, 19 Apr 2024 11:10:47 +0200
Subject: [PATCH 06/17] fix: always stop console timer

---
 examples/gauge/Components/InterfaceSample.tsx | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx
index 67de4a8..4a64e0b 100644
--- a/examples/gauge/Components/InterfaceSample.tsx
+++ b/examples/gauge/Components/InterfaceSample.tsx
@@ -78,10 +78,6 @@ export class InterfaceSample extends DisplayComponent {
     )
   }
 
-  public onBeforeRender(): void {
-    super.onBeforeRender()
-  }
-
   public onAfterRender(node: VNode): void {
     super.onAfterRender(node)
 
@@ -92,11 +88,9 @@ export class InterfaceSample extends DisplayComponent {
       console.time("query")
       this.navigationDataInterface
         .get_airport(this.inputRef.instance.value)
-        .then(airport => {
-          console.info(airport)
-          console.timeEnd("query")
-        })
+        .then(airport => console.info(airport))
         .catch(e => console.error(e))
+        .finally(() => console.timeEnd("query"))
     })
 
     AuthService.user.sub(user => {

From 7c852a192fc46e5536b7069fddd6387e10011626 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= 
Date: Fri, 19 Apr 2024 11:30:52 +0200
Subject: [PATCH 07/17] chore: execute SQL -> fetch airport

Since you can't actually input SQL
---
 examples/gauge/Components/InterfaceSample.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx
index 4a64e0b..4678224 100644
--- a/examples/gauge/Components/InterfaceSample.tsx
+++ b/examples/gauge/Components/InterfaceSample.tsx
@@ -70,7 +70,7 @@ export class InterfaceSample extends DisplayComponent {
             
- Execute SQL + Fetch Airport
From 69d728db77660a1e79b6658663ec79a4908d62e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 12:13:58 +0200 Subject: [PATCH 08/17] feat: channel key inputs to input when focused --- examples/gauge/Components/Input.tsx | 51 +++++++++++++++++++ examples/gauge/Components/InterfaceSample.tsx | 5 +- examples/gauge/global.d.ts | 15 ++++++ 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 examples/gauge/Components/Input.tsx create mode 100644 examples/gauge/global.d.ts diff --git a/examples/gauge/Components/Input.tsx b/examples/gauge/Components/Input.tsx new file mode 100644 index 0000000..fb42460 --- /dev/null +++ b/examples/gauge/Components/Input.tsx @@ -0,0 +1,51 @@ +import { ComponentProps, DisplayComponent, FSComponent, Subscribable, UUID, VNode } from "@microsoft/msfs-sdk" + +interface InputProps extends ComponentProps { + type: HTMLInputElement["type"] + name?: string + value?: string + class?: string | Subscribable +} + +export class Input extends DisplayComponent { + private readonly inputId = UUID.GenerateUuid() + private readonly inputRef = FSComponent.createRef() + + get value() { + return this.inputRef.instance.value + } + + onAfterRender(node: VNode): void { + super.onAfterRender(node) + + this.inputRef.instance.onfocus = this.onInputFocus + this.inputRef.instance.onblur = this.onInputBlur + } + + private getInputProps() { + return { name: this.props.name, value: this.props.value, class: this.props.class } + } + + /** + * Method to handle when input focus is set + * @param e The focus event. + */ + private onInputFocus = (e: FocusEvent): void => { + e.preventDefault() + + Coherent.trigger("FOCUS_INPUT_FIELD", this.inputId, "", "", this.inputRef.instance.value, false) + Coherent.on("mousePressOutsideView", () => this.inputRef.instance.blur()) + } + + /** + * Method to handle on input blur + */ + private onInputBlur = (): void => { + Coherent.trigger("UNFOCUS_INPUT_FIELD", "") + Coherent.off("mousePressOutsideView") + } + + render() { + return + } +} diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 4678224..a955ce6 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -9,6 +9,7 @@ import { NavigraphNavigationDataInterface, } from "@navigraph/msfs-navigation-data-interface" import { Dropdown } from "./Dropdown" +import { Input } from "./Input" interface InterfaceSampleProps extends ComponentProps { bus: EventBus @@ -22,7 +23,7 @@ export class InterfaceSample extends DisplayComponent { private readonly dropdownRef = FSComponent.createRef() private readonly downloadButtonRef = FSComponent.createRef() private readonly executeButtonRef = FSComponent.createRef() - private readonly inputRef = FSComponent.createRef() + private readonly inputRef = FSComponent.createRef() private cancelSource = CancelToken.source() @@ -68,7 +69,7 @@ export class InterfaceSample extends DisplayComponent {
Download
- +
Fetch Airport
diff --git a/examples/gauge/global.d.ts b/examples/gauge/global.d.ts new file mode 100644 index 0000000..2d5dd30 --- /dev/null +++ b/examples/gauge/global.d.ts @@ -0,0 +1,15 @@ +interface CoherentEngine { + /** + * Asynchronously call a C++ handler and retrieve the result + * @param name name of the C++ handler to be called + * @param args any extra parameters to be passed to the C++ handler + * @return promise for the result of the C++ function + */ + call(name: "PLAY_INSTRUMENT_SOUND", soundName: string): Promise + call(name: string, ...args: unknown[]): Promise + + on(name: "SetInputTextFromOS" | "mousePressOutsideView", cb: () => void): void + off(name: "SetInputTextFromOS" | "mousePressOutsideView", cb?: () => void): void + + trigger(name: "FOCUS_INPUT_FIELD" | "UNFOCUS_INPUT_FIELD", ...args: unknown[]) +} From 60898e814d40b1b77e28ec05feba3cbfb9be74a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 12:51:59 +0200 Subject: [PATCH 09/17] refactor: improve layout --- examples/gauge/Components/InterfaceSample.css | 27 +++++++++++++++---- examples/gauge/Components/InterfaceSample.tsx | 21 ++++++++++++++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/examples/gauge/Components/InterfaceSample.css b/examples/gauge/Components/InterfaceSample.css index 5ec8e0a..1807453 100644 --- a/examples/gauge/Components/InterfaceSample.css +++ b/examples/gauge/Components/InterfaceSample.css @@ -3,7 +3,6 @@ width: 100%; height: 100%; position: relative; - top: 100px; } .button { @@ -19,16 +18,21 @@ } .qr-code { - width: 300px; - height: 300px; + margin-top: 10px; + width: 250px; + height: 250px; display: none; + background: white; + padding: 10px; + border-radius: 5px; } .horizontal { display: flex; flex-direction: row; - justify-content: center; - align-items: center; + justify-content: space-evenly; + align-items: flex-start; + padding: 2rem; } .vertical { @@ -49,3 +53,16 @@ justify-content: center; align-items: center; } + +pre { + background: #272727; + border-radius: 6px; + padding: 10px; + + min-width: 300px; + min-height: 200px; +} + +h4 { + margin-bottom: 15px; +} diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index a955ce6..13f658d 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -24,6 +24,7 @@ export class InterfaceSample extends DisplayComponent { private readonly downloadButtonRef = FSComponent.createRef() private readonly executeButtonRef = FSComponent.createRef() private readonly inputRef = FSComponent.createRef() + private readonly outputRef = FSComponent.createRef() private cancelSource = CancelToken.source() @@ -59,21 +60,32 @@ export class InterfaceSample extends DisplayComponent {
+

Step 1 - Sign in

Loading
+

Step 2 - Select Database

Download
+
+
+ +

Step 3 - Query the database

+
+
Fetch Airport
+
+            The output of the query will show up here
+          
) @@ -89,7 +101,11 @@ export class InterfaceSample extends DisplayComponent { console.time("query") this.navigationDataInterface .get_airport(this.inputRef.instance.value) - .then(airport => console.info(airport)) + .then(airport => { + console.info(airport) + + this.outputRef.instance.textContent = JSON.stringify(airport, null, 2) + }) .catch(e => console.error(e)) .finally(() => console.timeEnd("query")) }) @@ -100,6 +116,7 @@ export class InterfaceSample extends DisplayComponent { this.qrCodeRef.instance.style.display = "none" this.loginButtonRef.instance.textContent = "Log out" this.textRef.instance.textContent = `Welcome, ${user.preferred_username}` + this.displayMessage("") this.handleLogin() } else { @@ -115,6 +132,7 @@ export class InterfaceSample extends DisplayComponent { await AuthService.signOut() } else { this.cancelSource = CancelToken.source() // Reset any previous cancellations + this.displayMessage("Authenticating.. Scan code (or click it) to sign in") await AuthService.signIn(p => { if (p) { this.qrCodeRef.instance.src = `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${p.verification_uri_complete}` @@ -126,6 +144,7 @@ export class InterfaceSample extends DisplayComponent { }, this.cancelSource.token) } } catch (err) { + this.qrCodeRef.instance.style.display = "none" if (err instanceof Error) this.displayError(err.message) else this.displayError(`Unknown error: ${String(err)}`) } From bef2ef284ce50a4dc6aeb1b725799c65e7163da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 19 Apr 2024 14:01:27 +0200 Subject: [PATCH 10/17] feat: support raw SQL input --- examples/gauge/Components/Input.tsx | 11 ++++-- examples/gauge/Components/InterfaceSample.tsx | 37 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/examples/gauge/Components/Input.tsx b/examples/gauge/Components/Input.tsx index fb42460..a94c24a 100644 --- a/examples/gauge/Components/Input.tsx +++ b/examples/gauge/Components/Input.tsx @@ -1,10 +1,9 @@ import { ComponentProps, DisplayComponent, FSComponent, Subscribable, UUID, VNode } from "@microsoft/msfs-sdk" interface InputProps extends ComponentProps { - type: HTMLInputElement["type"] - name?: string value?: string class?: string | Subscribable + textarea?: boolean } export class Input extends DisplayComponent { @@ -23,7 +22,7 @@ export class Input extends DisplayComponent { } private getInputProps() { - return { name: this.props.name, value: this.props.value, class: this.props.class } + return { value: this.props.value, class: this.props.class } } /** @@ -46,6 +45,12 @@ export class Input extends DisplayComponent { } render() { + if (this.props.textarea) + return ( + + ) return } } diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 13f658d..344a760 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -22,8 +22,10 @@ export class InterfaceSample extends DisplayComponent { private readonly qrCodeRef = FSComponent.createRef() private readonly dropdownRef = FSComponent.createRef() private readonly downloadButtonRef = FSComponent.createRef() - private readonly executeButtonRef = FSComponent.createRef() - private readonly inputRef = FSComponent.createRef() + private readonly icaoInputRef = FSComponent.createRef() + private readonly executeIcaoButtonRef = FSComponent.createRef() + private readonly sqlInputRef = FSComponent.createRef() + private readonly executeSqlButtonRef = FSComponent.createRef() private readonly outputRef = FSComponent.createRef() private cancelSource = CancelToken.source() @@ -78,10 +80,20 @@ export class InterfaceSample extends DisplayComponent {

Step 3 - Query the database

- -
+ +
Fetch Airport
+
+ +
+ Execute SQL +
             The output of the query will show up here
@@ -97,19 +109,30 @@ export class InterfaceSample extends DisplayComponent {
     this.loginButtonRef.instance.addEventListener("click", () => this.handleClick())
     this.downloadButtonRef.instance.addEventListener("click", () => this.handleDownloadClick())
 
-    this.executeButtonRef.instance.addEventListener("click", () => {
+    this.executeIcaoButtonRef.instance.addEventListener("click", () => {
       console.time("query")
       this.navigationDataInterface
-        .get_airport(this.inputRef.instance.value)
+        .get_airport(this.icaoInputRef.instance.value)
         .then(airport => {
           console.info(airport)
-
           this.outputRef.instance.textContent = JSON.stringify(airport, null, 2)
         })
         .catch(e => console.error(e))
         .finally(() => console.timeEnd("query"))
     })
 
+    this.executeSqlButtonRef.instance.addEventListener("click", () => {
+      console.time("query")
+      this.navigationDataInterface
+        .execute_sql(this.sqlInputRef.instance.value, [])
+        .then(result => {
+          console.info(result)
+          this.outputRef.instance.textContent = JSON.stringify(result, null, 2)
+        })
+        .catch(e => console.error(e))
+        .finally(() => console.timeEnd("query"))
+    })
+
     AuthService.user.sub(user => {
       if (user) {
         this.qrCodeRef.instance.src = ""

From 22c4a6799e98293c01851286758b7470a481a1e5 Mon Sep 17 00:00:00 2001
From: Jack Lavigne 
Date: Tue, 7 May 2024 20:26:06 -0400
Subject: [PATCH 11/17] fix: typos in NavigationDataStatus

---
 src/js/types/meta.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/js/types/meta.ts b/src/js/types/meta.ts
index 86fc0c2..79b3407 100644
--- a/src/js/types/meta.ts
+++ b/src/js/types/meta.ts
@@ -7,9 +7,9 @@ export enum InstallStatus {
 export interface NavigationDataStatus {
   status: InstallStatus
   installedFormat: string | null
-  installedRegion: string | null
+  installedRevision: string | null
   installedCycle: string | null
   installedPath: string | null
   validityPeriod: string | null
-  lastestCycle: string | null
+  latestCycle: string | null
 }

From 93b96aa17568145e589d9e4bd4aab0b30afbb6b5 Mon Sep 17 00:00:00 2001
From: Jack Lavigne 
Date: Tue, 7 May 2024 20:26:21 -0400
Subject: [PATCH 12/17] feat: display install status on display

---
 examples/gauge/Components/Input.tsx           |  2 +-
 examples/gauge/Components/InterfaceSample.tsx | 64 ++++++++++++++++++-
 2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/examples/gauge/Components/Input.tsx b/examples/gauge/Components/Input.tsx
index a94c24a..f88a160 100644
--- a/examples/gauge/Components/Input.tsx
+++ b/examples/gauge/Components/Input.tsx
@@ -47,7 +47,7 @@ export class Input extends DisplayComponent {
   render() {
     if (this.props.textarea)
       return (
-        
       )
diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx
index 344a760..464e69b 100644
--- a/examples/gauge/Components/InterfaceSample.tsx
+++ b/examples/gauge/Components/InterfaceSample.tsx
@@ -1,4 +1,13 @@
-import { ComponentProps, DisplayComponent, EventBus, FSComponent, VNode } from "@microsoft/msfs-sdk"
+import {
+  ComponentProps,
+  DisplayComponent,
+  EventBus,
+  FSComponent,
+  MappedSubject,
+  ObjectSubject,
+  Subject,
+  VNode,
+} from "@microsoft/msfs-sdk"
 import { CancelToken } from "navigraph/auth"
 import { packages } from "../Lib/navigraph"
 import { AuthService } from "../Services/AuthService"
@@ -8,6 +17,7 @@ import {
   NavigraphEventType,
   NavigraphNavigationDataInterface,
 } from "@navigraph/msfs-navigation-data-interface"
+import { NavigationDataStatus } from "@navigraph/msfs-navigation-data-interface/types/meta"
 import { Dropdown } from "./Dropdown"
 import { Input } from "./Input"
 
@@ -28,6 +38,8 @@ export class InterfaceSample extends DisplayComponent {
   private readonly executeSqlButtonRef = FSComponent.createRef()
   private readonly outputRef = FSComponent.createRef()
 
+  private readonly navigationDataStatus = Subject.create(null)
+
   private cancelSource = CancelToken.source()
 
   private navigationDataInterface: NavigraphNavigationDataInterface
@@ -57,6 +69,36 @@ export class InterfaceSample extends DisplayComponent {
     })
   }
 
+  public renderDatabaseStatus(): VNode | void {
+    return (
+      <>
+        
{ + return status ? "vertical" : "hidden" + }, this.navigationDataStatus)} + > +
{this.navigationDataStatus.map(s => `Install method: ${s?.status}`)}
+
+ {this.navigationDataStatus.map( + s => `Installed format: ${s?.installedFormat} revision ${s?.installedRevision}`, + )} +
+
{this.navigationDataStatus.map(s => `Installed path: ${s?.installedPath}`)}
+
{this.navigationDataStatus.map(s => `Installed cycle: ${s?.installedCycle}`)}
+
{this.navigationDataStatus.map(s => `Latest cycle: ${s?.latestCycle}`)}
+
{this.navigationDataStatus.map(s => `Validity period: ${s?.validityPeriod}`)}
+
+
{ + return status ? "hidden" : "visible" + }, this.navigationDataStatus)} + > + Loading status... +
+ + ) + } + public render(): VNode { return (
@@ -74,6 +116,7 @@ export class InterfaceSample extends DisplayComponent {
Download
+ {this.renderDatabaseStatus()}
@@ -109,6 +152,16 @@ export class InterfaceSample extends DisplayComponent { this.loginButtonRef.instance.addEventListener("click", () => this.handleClick()) this.downloadButtonRef.instance.addEventListener("click", () => this.handleDownloadClick()) + // Populate status when ready + this.navigationDataInterface.onReady(() => { + this.navigationDataInterface + .get_navigation_data_install_status() + .then(status => { + this.navigationDataStatus.set(status) + }) + .catch(e => console.error(e)) + }) + this.executeIcaoButtonRef.instance.addEventListener("click", () => { console.time("query") this.navigationDataInterface @@ -197,6 +250,15 @@ export class InterfaceSample extends DisplayComponent { // Download navigation data to work dir await this.navigationDataInterface.download_navigation_data(pkg.file.url) + + // Update navigation data status + this.navigationDataInterface + .get_navigation_data_install_status() + .then(status => { + this.navigationDataStatus.set(status) + }) + .catch(e => console.error(e)) + this.displayMessage("Navigation data downloaded") } catch (err) { if (err instanceof Error) this.displayError(err.message) From 448e70aaa71780540b8b21a412d45f8c16a14ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Hallstr=C3=B6m?= Date: Fri, 10 May 2024 14:38:38 +0200 Subject: [PATCH 13/17] refactor: mappedsubject -> .map, unused import --- examples/gauge/Components/InterfaceSample.tsx | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 464e69b..d39b9a3 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -4,22 +4,21 @@ import { EventBus, FSComponent, MappedSubject, - ObjectSubject, Subject, VNode, } from "@microsoft/msfs-sdk" -import { CancelToken } from "navigraph/auth" -import { packages } from "../Lib/navigraph" -import { AuthService } from "../Services/AuthService" -import "./InterfaceSample.css" import { DownloadProgressPhase, NavigraphEventType, NavigraphNavigationDataInterface, } from "@navigraph/msfs-navigation-data-interface" import { NavigationDataStatus } from "@navigraph/msfs-navigation-data-interface/types/meta" +import { CancelToken } from "navigraph/auth" +import { packages } from "../Lib/navigraph" +import { AuthService } from "../Services/AuthService" import { Dropdown } from "./Dropdown" import { Input } from "./Input" +import "./InterfaceSample.css" interface InterfaceSampleProps extends ComponentProps { bus: EventBus @@ -88,13 +87,7 @@ export class InterfaceSample extends DisplayComponent {
{this.navigationDataStatus.map(s => `Latest cycle: ${s?.latestCycle}`)}
{this.navigationDataStatus.map(s => `Validity period: ${s?.validityPeriod}`)}
-
{ - return status ? "hidden" : "visible" - }, this.navigationDataStatus)} - > - Loading status... -
+
(status ? "hidden" : "visible"))}>Loading status...
) } @@ -156,9 +149,7 @@ export class InterfaceSample extends DisplayComponent { this.navigationDataInterface.onReady(() => { this.navigationDataInterface .get_navigation_data_install_status() - .then(status => { - this.navigationDataStatus.set(status) - }) + .then(status => this.navigationDataStatus.set(status)) .catch(e => console.error(e)) }) @@ -254,9 +245,7 @@ export class InterfaceSample extends DisplayComponent { // Update navigation data status this.navigationDataInterface .get_navigation_data_install_status() - .then(status => { - this.navigationDataStatus.set(status) - }) + .then(status => this.navigationDataStatus.set(status)) .catch(e => console.error(e)) this.displayMessage("Navigation data downloaded") From f155c046a209923ec84d4802a1457fa09531febb Mon Sep 17 00:00:00 2001 From: Jack Lavigne Date: Fri, 10 May 2024 16:59:44 -0400 Subject: [PATCH 14/17] feat: add loading screen while waiting for wasm to build --- examples/gauge/Components/InterfaceSample.css | 10 ++ examples/gauge/Components/InterfaceSample.tsx | 102 ++++++++++-------- 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/examples/gauge/Components/InterfaceSample.css b/examples/gauge/Components/InterfaceSample.css index 1807453..cdce921 100644 --- a/examples/gauge/Components/InterfaceSample.css +++ b/examples/gauge/Components/InterfaceSample.css @@ -5,6 +5,16 @@ position: relative; } +.loading-container { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + font-size: x-large; + text-align: center; +} + .button { width: 150px; height: 50px; diff --git a/examples/gauge/Components/InterfaceSample.tsx b/examples/gauge/Components/InterfaceSample.tsx index 464e69b..b94e0b6 100644 --- a/examples/gauge/Components/InterfaceSample.tsx +++ b/examples/gauge/Components/InterfaceSample.tsx @@ -6,6 +6,7 @@ import { MappedSubject, ObjectSubject, Subject, + SubscribableMapFunctions, VNode, } from "@microsoft/msfs-sdk" import { CancelToken } from "navigraph/auth" @@ -39,6 +40,7 @@ export class InterfaceSample extends DisplayComponent { private readonly outputRef = FSComponent.createRef() private readonly navigationDataStatus = Subject.create(null) + private readonly interfaceInitialized = Subject.create(false) private cancelSource = CancelToken.source() @@ -49,6 +51,18 @@ export class InterfaceSample extends DisplayComponent { this.navigationDataInterface = new NavigraphNavigationDataInterface() + // Populate status when ready + this.navigationDataInterface.onReady(() => { + this.navigationDataInterface + .get_navigation_data_install_status() + .then(status => { + this.navigationDataStatus.set(status) + }) + .catch(e => console.error(e)) + + this.interfaceInitialized.set(true) + }) + this.navigationDataInterface.onEvent(NavigraphEventType.DownloadProgress, data => { switch (data.phase) { case DownloadProgressPhase.Downloading: @@ -101,48 +115,54 @@ export class InterfaceSample extends DisplayComponent { public render(): VNode { return ( -
-
-
-

Step 1 - Sign in

-
Loading
-
-
- -
-
-

Step 2 - Select Database

- -
- Download + <> + +