fix(ui): ensure app is initialized independently of the WS status
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 28 Feb 2024 22:38:20 +0000 (23:38 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 28 Feb 2024 22:38:20 +0000 (23:38 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
ui/web/src/composables/UIClient.ts
ui/web/src/main.ts
ui/web/src/views/ChargingStationsView.vue

index bd0208ad007f833c368c0543ede372c15a9dd003..d7a5eb3df6b7d270b733438171a27bdfb5f10faf 100644 (file)
@@ -20,7 +20,7 @@ type ResponseHandler = {
 export class UIClient {
   private static instance: UIClient | null = null
 
-  private ws!: WebSocket
+  private ws?: WebSocket
   private responseHandlers: Map<string, ResponseHandler>
 
   private constructor(private uiServerConfiguration: UIServerConfigurationSection) {
@@ -36,7 +36,10 @@ export class UIClient {
   }
 
   public setConfiguration(uiServerConfiguration: UIServerConfigurationSection): void {
-    this.ws.close()
+    if (this.ws?.readyState === WebSocket.OPEN) {
+      this.ws.close()
+      delete this.ws
+    }
     this.uiServerConfiguration = uiServerConfiguration
     this.openWS()
   }
@@ -46,7 +49,7 @@ export class UIClient {
     listener: (event: WebSocketEventMap[K]) => void,
     options?: boolean | AddEventListenerOptions
   ) {
-    this.ws.addEventListener(event, listener, options)
+    this.ws?.addEventListener(event, listener, options)
   }
 
   public async startSimulator(): Promise<ResponsePayload> {
@@ -186,7 +189,7 @@ export class UIClient {
     payload: RequestPayload
   ): Promise<ResponsePayload> {
     return new Promise<ResponsePayload>((resolve, reject) => {
-      if (this.ws.readyState === WebSocket.OPEN) {
+      if (this.ws?.readyState === WebSocket.OPEN) {
         const uuid = crypto.randomUUID()
         const msg = JSON.stringify([uuid, procedureName, payload])
         const sendTimeout = setTimeout(() => {
index 0e79968462d64a39b87bd39afc86d0b3feaea48a..8c16f4a7fefe0fadd3d157cea469e9e0d3ba5fba 100644 (file)
@@ -1,6 +1,6 @@
 import { type App as AppType, createApp } from 'vue'
 import ToastPlugin from 'vue-toast-notification'
-import type { ConfigurationData, ResponsePayload } from '@/types'
+import type { ConfigurationData } from '@/types'
 import { router } from '@/router'
 import { UIClient, getFromLocalStorage, setToLocalStorage } from '@/composables'
 import App from '@/App.vue'
@@ -37,25 +37,8 @@ const initializeApp = (app: AppType, config: ConfigurationData) => {
         getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
       ]
     )
-    app.config.globalProperties.$uiClient.registerWSEventListener(
-      'open',
-      () => {
-        app.config.globalProperties.$uiClient
-          .listChargingStations()
-          .then((response: ResponsePayload) => {
-            app.config.globalProperties.$chargingStations = response.chargingStations
-          })
-          .catch((error: Error) => {
-            // TODO: add code for UI notifications or other error handling logic
-            console.error('Error at fetching charging stations:', error)
-          })
-          .finally(() => {
-            app.use(router).use(ToastPlugin).mount('#app')
-          })
-      },
-      { once: true }
-    )
   }
+  app.use(router).use(ToastPlugin).mount('#app')
 }
 
 fetch('/config.json')
@@ -68,12 +51,7 @@ fetch('/config.json')
     response
       .json()
       .then(config => {
-        try {
-          initializeApp(app, config)
-        } catch (error) {
-          // TODO: add code for UI notifications or other error handling logic
-          console.error('Error at initializing app:', error)
-        }
+        initializeApp(app, config)
       })
       .catch(error => {
         // TODO: add code for UI notifications or other error handling logic
index abea2075cc1207114d0a0d1174f5b1453058a709..03f73d638daa76af6472ba6547834c7ac3365f9b 100644 (file)
@@ -9,34 +9,33 @@
         v-model="state.uiServerIndex"
         @change="
           () => {
-            try {
-              if (
-                getFromLocalStorage<number>('uiServerConfigurationIndex', 0) !== state.uiServerIndex
-              ) {
-                setToLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
-                app?.appContext.config.globalProperties.$uiClient.registerWSEventListener(
-                  'close',
-                  () => {
-                    app!.appContext.config.globalProperties.$chargingStations = []
-                  },
-                  { once: true }
-                )
-                app?.appContext.config.globalProperties.$uiClient.setConfiguration(
-                  app?.appContext.config.globalProperties.$configuration.uiServer[
-                    getFromLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
-                  ]
-                )
-                app?.appContext.config.globalProperties.$uiClient.registerWSEventListener(
-                  'open',
-                  () => {
-                    loadChargingStations(() => (state.renderChargingStationsList = randomUUID()))
-                  },
-                  { once: true }
-                )
-              }
-            } catch (error) {
-              $toast.error('Error at changing UI server configuration')
-              console.error('Error at changing UI server configuration:', error)
+            if (
+              getFromLocalStorage<number>('uiServerConfigurationIndex', 0) !== state.uiServerIndex
+            ) {
+              app?.appContext.config.globalProperties.$uiClient.setConfiguration(
+                app?.appContext.config.globalProperties.$configuration.uiServer[state.uiServerIndex]
+              )
+              initializeWSEventListeners()
+              app?.appContext.config.globalProperties.$uiClient.registerWSEventListener(
+                'open',
+                () => {
+                  setToLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
+                },
+                { once: true }
+              )
+              app?.appContext.config.globalProperties.$uiClient.registerWSEventListener(
+                'error',
+                () => {
+                  state.uiServerIndex = getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
+                  app?.appContext.config.globalProperties.$uiClient.setConfiguration(
+                    app?.appContext.config.globalProperties.$configuration.uiServer[
+                      getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
+                    ]
+                  )
+                  initializeWSEventListeners()
+                },
+                { once: true }
+              )
             }
           }
         "
@@ -73,7 +72,7 @@
 </template>
 
 <script setup lang="ts">
-import { getCurrentInstance, reactive } from 'vue'
+import { getCurrentInstance, onMounted, reactive } from 'vue'
 import { useToast } from 'vue-toast-notification'
 import CSTable from '@/components/charging-stations/CSTable.vue'
 import type { ResponsePayload, UIServerConfigurationSection } from '@/types'
@@ -86,13 +85,32 @@ const randomUUID = (): `${string}-${string}-${string}-${string}-${string}` => {
   return crypto.randomUUID()
 }
 
+const app = getCurrentInstance()
+
+const initializeWSEventListeners = () => {
+  app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('open', () => {
+    loadChargingStations(() => (state.renderChargingStationsList = randomUUID()))
+  })
+  app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('error', () => {
+    app.appContext.config.globalProperties.$chargingStations = []
+    state.renderChargingStationsList = randomUUID()
+  })
+  app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('close', () => {
+    app.appContext.config.globalProperties.$chargingStations = []
+    state.renderChargingStationsList = randomUUID()
+  })
+}
+
+onMounted(() => {
+  initializeWSEventListeners()
+})
+
 const state = reactive({
   renderChargingStationsList: randomUUID(),
   loading: false,
   uiServerIndex: getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
 })
 
-const app = getCurrentInstance()
 const uiClient = app?.appContext.config.globalProperties.$uiClient
 const uiServerConfigurations: { configuration: UIServerConfigurationSection; index: number }[] =
   app?.appContext.config.globalProperties.$configuration.uiServer.map(
@@ -115,6 +133,9 @@ const loadChargingStations = (renderCallback?: () => void): void => {
         }
       })
       .catch((error: Error) => {
+        if (app != null) {
+          app.appContext.config.globalProperties.$chargingStations = []
+        }
         $toast.error('Error at fetching charging stations')
         console.error('Error at fetching charging stations:', error)
       })