feat(ui): use toggle button to star/stop simulator
[e-mobility-charging-stations-simulator.git] / ui / web / src / views / ChargingStationsView.vue
index cb8d607d6b79911560061832ff980e8168639db7..57ae3e20d7f0ba65d57a1933b1b483887f739189 100644 (file)
@@ -9,20 +9,36 @@
         v-model="state.uiServerIndex"
         @change="
           () => {
-            try {
-              if (
-                getFromLocalStorage<number>('uiServerConfigurationIndex', 0) !== state.uiServerIndex
-              ) {
-                setToLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
-                app!.appContext.config.globalProperties.$uiClient.setConfiguration(
-                  app?.appContext.config.globalProperties.$configuration.uiServer[
-                    getFromLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
-                  ]
-                )
-              }
-            } 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)
+                  clearToggleButtons()
+                  $router.currentRoute.value.name !== 'charging-stations' &&
+                    $router.push({ name: 'charging-stations' })
+                },
+                { 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 }
+              )
             }
           }
         "
           v-for="uiServerConfiguration in uiServerConfigurations"
           :value="uiServerConfiguration.index"
         >
-          {{ uiServerConfiguration.configuration.host }}
+          {{ uiServerConfiguration.configuration.name ?? uiServerConfiguration.configuration.host }}
         </option>
       </select>
     </Container>
     <Container id="buttons-container">
-      <Button @click="startSimulator()">Start Simulator</Button>
-      <Button @click="stopSimulator()">Stop Simulator</Button>
-      <Button @click="$router.push({ name: 'add-charging-stations' })">
+      <ToggleButton
+        :id="'simulator'"
+        :key="state.renderSimulator"
+        :status="state.simulatorState?.started"
+        :on="() => startSimulator()"
+        :off="() => stopSimulator()"
+      >
+        {{ state.simulatorState?.started === true ? 'Stop' : 'Start' }} Simulator
+      </ToggleButton>
+      <ToggleButton
+        :id="'add-charging-stations'"
+        :key="state.renderAddChargingStations"
+        :shared="true"
+        :on="
+          () => {
+            $router.push({ name: 'add-charging-stations' })
+          }
+        "
+        :off="
+          () => {
+            $router.push({ name: 'charging-stations' })
+          }
+        "
+        @clicked="
+          () => {
+            state.renderChargingStations = randomUUID()
+          }
+        "
+      >
         Add Charging Stations
-      </Button>
+      </ToggleButton>
       <ReloadButton
         id="reload-button"
-        :loading="state.isLoading"
-        @click="loadChargingStations(() => $router.go(0))"
+        :loading="state.loading"
+        @click="loadChargingStations(() => (state.renderChargingStations = randomUUID()))"
       />
     </Container>
     <CSTable
       v-show="
         Array.isArray(app?.appContext.config.globalProperties.$chargingStations) &&
-        app?.appContext.config.globalProperties.$chargingStations.length > 0
+        app.appContext.config.globalProperties.$chargingStations.length > 0
       "
+      :key="state.renderChargingStations"
       :charging-stations="app?.appContext.config.globalProperties.$chargingStations"
+      @need-refresh="
+        () => {
+          state.renderAddChargingStations = randomUUID()
+          state.renderChargingStations = randomUUID()
+        }
+      "
     />
   </Container>
 </template>
 
 <script setup lang="ts">
-import { getCurrentInstance, reactive } from 'vue'
+import { getCurrentInstance, onMounted, ref } from 'vue'
 import { useToast } from 'vue-toast-notification'
 import CSTable from '@/components/charging-stations/CSTable.vue'
 import type { ResponsePayload, UIServerConfigurationSection } from '@/types'
 import Container from '@/components/Container.vue'
 import ReloadButton from '@/components/buttons/ReloadButton.vue'
-import Button from '@/components/buttons/Button.vue'
-import { getFromLocalStorage, setToLocalStorage } from '@/composables'
+import {
+  getFromLocalStorage,
+  getLocalStorage,
+  randomUUID,
+  removeFromLocalStorage,
+  setToLocalStorage
+} from '@/composables'
+import ToggleButton from '@/components/buttons/ToggleButton.vue'
 
-const state = reactive({
-  isLoading: false,
+const state = ref<{
+  renderSimulator: `${string}-${string}-${string}-${string}-${string}`
+  renderAddChargingStations: `${string}-${string}-${string}-${string}-${string}`
+  renderChargingStations: `${string}-${string}-${string}-${string}-${string}`
+  loading: boolean
+  simulatorState?: { started: boolean }
+  uiServerIndex: number
+}>({
+  renderSimulator: randomUUID(),
+  renderAddChargingStations: randomUUID(),
+  renderChargingStations: randomUUID(),
+  loading: false,
   uiServerIndex: getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
 })
 
 const app = getCurrentInstance()
+
+const clearToggleButtons = (): void => {
+  for (const key in getLocalStorage()) {
+    if (key.includes('toggle-button')) {
+      removeFromLocalStorage(key)
+    }
+  }
+}
+
+const clearChargingStations = (): void => {
+  app!.appContext.config.globalProperties.$chargingStations = []
+  state.value.renderChargingStations = randomUUID()
+}
+
 const uiClient = app?.appContext.config.globalProperties.$uiClient
+
+const getSimulatorState = (): void => {
+  uiClient
+    .simulatorState()
+    .then((response: ResponsePayload) => {
+      state.value.simulatorState = response.state as { started: boolean }
+    })
+    .catch((error: Error) => {
+      $toast.error('Error at fetching simulator state')
+      console.error('Error at fetching simulator state:', error)
+    })
+    .finally(() => {
+      state.value.renderSimulator = randomUUID()
+    })
+}
+
+const initializeWSEventListeners = () => {
+  app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('open', () => {
+    getSimulatorState()
+    uiClient
+      .listTemplates()
+      .then((response: ResponsePayload) => {
+        if (app != null) {
+          app.appContext.config.globalProperties.$templates = response.templates
+        }
+      })
+      .catch((error: Error) => {
+        if (app != null) {
+          app.appContext.config.globalProperties.$templates = []
+        }
+        $toast.error('Error at fetching charging station templates')
+        console.error('Error at fetching charging station templates:', error)
+      })
+      .finally(() => {
+        state.value.renderAddChargingStations = randomUUID()
+      })
+    loadChargingStations(() => {
+      state.value.renderChargingStations = randomUUID()
+    })
+  })
+  app?.appContext.config.globalProperties.$uiClient.registerWSEventListener(
+    'error',
+    clearChargingStations
+  )
+  app?.appContext.config.globalProperties.$uiClient.registerWSEventListener(
+    'close',
+    clearChargingStations
+  )
+}
+
+onMounted(() => {
+  initializeWSEventListeners()
+})
+
 const uiServerConfigurations: { configuration: UIServerConfigurationSection; index: number }[] =
   app?.appContext.config.globalProperties.$configuration.uiServer.map(
     (configuration: UIServerConfigurationSection, index: number) => ({
@@ -84,9 +217,9 @@ const uiServerConfigurations: { configuration: UIServerConfigurationSection; ind
 
 const $toast = useToast()
 
-const loadChargingStations = (reloadCallback?: () => void): void => {
-  if (state.isLoading === false) {
-    state.isLoading = true
+const loadChargingStations = (renderCallback?: () => void): void => {
+  if (state.value.loading === false) {
+    state.value.loading = true
     uiClient
       .listChargingStations()
       .then((response: ResponsePayload) => {
@@ -95,14 +228,17 @@ const loadChargingStations = (reloadCallback?: () => 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)
       })
       .finally(() => {
-        if (reloadCallback != null) {
-          reloadCallback()
+        if (renderCallback != null) {
+          renderCallback()
         }
-        state.isLoading = false
+        state.value.loading = false
       })
   }
 }
@@ -117,6 +253,9 @@ const startSimulator = (): void => {
       $toast.error('Error at starting simulator')
       console.error('Error at starting simulator:', error)
     })
+    .finally(() => {
+      getSimulatorState()
+    })
 }
 const stopSimulator = (): void => {
   uiClient
@@ -131,6 +270,9 @@ const stopSimulator = (): void => {
       $toast.error('Error at stopping simulator')
       console.error('Error at stopping simulator:', error)
     })
+    .finally(() => {
+      getSimulatorState()
+    })
 }
 </script>
 
@@ -176,7 +318,7 @@ const stopSimulator = (): void => {
 }
 
 #reload-button:active {
-  background-color: red;
+  background-color: seagreen;
 }
 
 #action {