feat(ui): add 'Not found' catch all
[e-mobility-charging-stations-simulator.git] / ui / web / src / views / ChargingStationsView.vue
CommitLineData
32de5a57 1<template>
ca1e5439 2 <Container id="charging-stations-container">
239bd875
JB
3 <Container id="buttons-container">
4 <Container
5 v-show="Array.isArray(uiServerConfigurations) && uiServerConfigurations.length > 1"
6 id="ui-server-container"
0344ad2b 7 >
239bd875
JB
8 <select
9 id="ui-server-selector"
10 v-model="state.uiServerIndex"
11 @change="
12 () => {
13 if (
14 getFromLocalStorage<number>('uiServerConfigurationIndex', 0) !== state.uiServerIndex
15 ) {
7e315430 16 $uiClient.setConfiguration($configuration.value.uiServer[state.uiServerIndex])
aa9b0a1e 17 registerWSEventListeners()
7e315430 18 $uiClient.registerWSEventListener(
239bd875
JB
19 'open',
20 () => {
21 setToLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
22 clearToggleButtons()
877b880c 23 $route.name !== 'charging-stations' &&
239bd875
JB
24 $router.push({ name: 'charging-stations' })
25 },
26 { once: true }
27 )
7e315430 28 $uiClient.registerWSEventListener(
239bd875
JB
29 'error',
30 () => {
31 state.uiServerIndex = getFromLocalStorage<number>(
32 'uiServerConfigurationIndex',
33 0
34 )
7e315430
JB
35 $uiClient.setConfiguration(
36 $configuration.value.uiServer[
239bd875
JB
37 getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
38 ]
39 )
aa9b0a1e 40 registerWSEventListeners()
239bd875
JB
41 },
42 { once: true }
43 )
44 }
45 }
46 "
0344ad2b 47 >
239bd875
JB
48 <option
49 v-for="uiServerConfiguration in uiServerConfigurations"
50 :value="uiServerConfiguration.index"
51 >
52 {{
53 uiServerConfiguration.configuration.name ?? uiServerConfiguration.configuration.host
54 }}
55 </option>
56 </select>
57 </Container>
240fa4da
JB
58 <ToggleButton
59 :id="'simulator'"
60 :key="state.renderSimulator"
61 :status="state.simulatorState?.started"
62 :on="() => startSimulator()"
63 :off="() => stopSimulator()"
ec7366ed 64 :class="simulatorButtonClass"
240fa4da 65 >
ec7366ed 66 {{ simulatorButtonMessage }}
240fa4da 67 </ToggleButton>
2610da71
JB
68 <ToggleButton
69 :id="'add-charging-stations'"
d64ea57b 70 :key="state.renderAddChargingStations"
2610da71
JB
71 :shared="true"
72 :on="
73 () => {
74 $router.push({ name: 'add-charging-stations' })
75 }
76 "
77 :off="
78 () => {
79 $router.push({ name: 'charging-stations' })
80 }
81 "
83468764
JB
82 @clicked="
83 () => {
84 state.renderChargingStations = randomUUID()
85 }
86 "
2610da71 87 >
1eb5f592 88 Add Charging Stations
2610da71 89 </ToggleButton>
b9d447d2
JB
90 <ReloadButton
91 id="reload-button"
26cf7d99
JB
92 :loading="state.gettingChargingStations"
93 @click="getChargingStations()"
b9d447d2 94 />
13c19b7b 95 </Container>
5c0e9352 96 <CSTable
7e315430 97 v-show="Array.isArray($chargingStations.value) && $chargingStations.value.length > 0"
3eea3ebc 98 :key="state.renderChargingStations"
7e315430 99 :charging-stations="$chargingStations.value"
83468764
JB
100 @need-refresh="
101 () => {
102 state.renderAddChargingStations = randomUUID()
103 state.renderChargingStations = randomUUID()
104 }
105 "
5c0e9352 106 />
32de5a57
LM
107 </Container>
108</template>
109
110<script setup lang="ts">
aa9b0a1e 111import { computed, getCurrentInstance, onMounted, onUnmounted, ref } from 'vue'
cea23fa0 112import { useToast } from 'vue-toast-notification'
66a7748d 113import CSTable from '@/components/charging-stations/CSTable.vue'
e8237645 114import type { ResponsePayload, SimulatorState, UIServerConfigurationSection } from '@/types'
66a7748d
JB
115import Container from '@/components/Container.vue'
116import ReloadButton from '@/components/buttons/ReloadButton.vue'
2610da71 117import {
b767fda7 118 deleteFromLocalStorage,
2610da71
JB
119 getFromLocalStorage,
120 getLocalStorage,
121 randomUUID,
39cd8fcb
JB
122 setToLocalStorage,
123 useUIClient
2610da71
JB
124} from '@/composables'
125import ToggleButton from '@/components/buttons/ToggleButton.vue'
a4868fd7 126
240fa4da
JB
127const state = ref<{
128 renderSimulator: `${string}-${string}-${string}-${string}-${string}`
129 renderAddChargingStations: `${string}-${string}-${string}-${string}-${string}`
130 renderChargingStations: `${string}-${string}-${string}-${string}-${string}`
26cf7d99
JB
131 gettingSimulatorState: boolean
132 gettingTemplates: boolean
133 gettingChargingStations: boolean
e8237645 134 simulatorState?: SimulatorState
240fa4da
JB
135 uiServerIndex: number
136}>({
137 renderSimulator: randomUUID(),
138 renderAddChargingStations: randomUUID(),
139 renderChargingStations: randomUUID(),
26cf7d99
JB
140 gettingSimulatorState: false,
141 gettingTemplates: false,
142 gettingChargingStations: false,
240fa4da
JB
143 uiServerIndex: getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
144})
145
ec7366ed
JB
146const simulatorButtonClass = computed<string>(() =>
147 state.value.simulatorState?.started === true ? 'simulator-stop-button' : 'simulator-start-button'
148)
149const simulatorButtonMessage = computed<string>(
150 () =>
1fa3425a 151 `${state.value.simulatorState?.started === true ? 'Stop' : 'Start'} Simulator${state.value.simulatorState?.version != null ? ` (${state.value.simulatorState.version})` : ''}`
ec7366ed
JB
152)
153
d64ea57b
JB
154const clearToggleButtons = (): void => {
155 for (const key in getLocalStorage()) {
156 if (key.includes('toggle-button')) {
b767fda7 157 deleteFromLocalStorage(key)
d64ea57b
JB
158 }
159 }
26cf7d99
JB
160 state.value.renderChargingStations = randomUUID()
161 state.value.renderAddChargingStations = randomUUID()
d64ea57b
JB
162}
163
97cd0ef3
JB
164const app = getCurrentInstance()
165
d64ea57b 166const clearChargingStations = (): void => {
26cf7d99 167 if (app != null) {
7e315430 168 app.appContext.config.globalProperties.$chargingStations.value = []
26cf7d99 169 }
3eea3ebc 170 state.value.renderChargingStations = randomUUID()
d64ea57b
JB
171}
172
39cd8fcb 173const uiClient = useUIClient()
240fa4da 174
97cd0ef3
JB
175const $toast = useToast()
176
240fa4da 177const getSimulatorState = (): void => {
26cf7d99
JB
178 if (state.value.gettingSimulatorState === false) {
179 state.value.gettingSimulatorState = true
3b0c6e17 180 uiClient
26cf7d99 181 .simulatorState()
3b0c6e17 182 .then((response: ResponsePayload) => {
26cf7d99 183 state.value.simulatorState = response.state as SimulatorState
3b0c6e17
JB
184 })
185 .catch((error: Error) => {
26cf7d99
JB
186 $toast.error('Error at fetching simulator state')
187 console.error('Error at fetching simulator state:', error)
3b0c6e17 188 })
240fa4da 189 .finally(() => {
26cf7d99
JB
190 state.value.renderSimulator = randomUUID()
191 state.value.gettingSimulatorState = false
240fa4da 192 })
26cf7d99
JB
193 }
194}
195
97cd0ef3
JB
196const getTemplates = (): void => {
197 if (state.value.gettingTemplates === false) {
198 state.value.gettingTemplates = true
199 uiClient
200 .listTemplates()
201 .then((response: ResponsePayload) => {
202 if (app != null) {
7e315430 203 app.appContext.config.globalProperties.$templates.value = response.templates
97cd0ef3
JB
204 }
205 })
206 .catch((error: Error) => {
207 if (app != null) {
7e315430 208 app.appContext.config.globalProperties.$templates.value = []
97cd0ef3
JB
209 }
210 $toast.error('Error at fetching charging station templates')
211 console.error('Error at fetching charging station templates:', error)
212 })
213 .finally(() => {
214 state.value.gettingTemplates = false
215 })
216 }
916fe456
JB
217}
218
26cf7d99
JB
219const getChargingStations = (): void => {
220 if (state.value.gettingChargingStations === false) {
221 state.value.gettingChargingStations = true
57c0ba05
JB
222 uiClient
223 .listChargingStations()
224 .then((response: ResponsePayload) => {
225 if (app != null) {
7e315430 226 app.appContext.config.globalProperties.$chargingStations.value = response.chargingStations
57c0ba05
JB
227 }
228 })
229 .catch((error: Error) => {
916fe456 230 if (app != null) {
7e315430 231 app.appContext.config.globalProperties.$chargingStations.value = []
916fe456 232 }
cea23fa0 233 $toast.error('Error at fetching charging stations')
57c0ba05
JB
234 console.error('Error at fetching charging stations:', error)
235 })
236 .finally(() => {
26cf7d99
JB
237 state.value.renderChargingStations = randomUUID()
238 state.value.gettingChargingStations = false
57c0ba05 239 })
2113b3c6 240 }
32de5a57 241}
5a010bf0 242
aa9b0a1e
JB
243const getData = (): void => {
244 getSimulatorState()
245 getTemplates()
246 getChargingStations()
247}
248
249const registerWSEventListeners = () => {
250 uiClient.registerWSEventListener('open', getData)
97cd0ef3
JB
251 uiClient.registerWSEventListener('error', clearChargingStations)
252 uiClient.registerWSEventListener('close', clearChargingStations)
253}
254
aa9b0a1e
JB
255const unregisterWSEventListeners = () => {
256 uiClient.unregisterWSEventListener('open', getData)
257 uiClient.unregisterWSEventListener('error', clearChargingStations)
258 uiClient.unregisterWSEventListener('close', clearChargingStations)
259}
260
97cd0ef3 261onMounted(() => {
aa9b0a1e
JB
262 registerWSEventListeners()
263})
264
265onUnmounted(() => {
266 unregisterWSEventListeners()
97cd0ef3
JB
267})
268
269const uiServerConfigurations: { index: number; configuration: UIServerConfigurationSection }[] =
7e315430 270 app?.appContext.config.globalProperties.$configuration.value.uiServer.map(
97cd0ef3
JB
271 (configuration: UIServerConfigurationSection, index: number) => ({
272 index,
273 configuration
274 })
275 )
276
fa5d129a 277const startSimulator = (): void => {
cea23fa0
JB
278 uiClient
279 .startSimulator()
280 .then(() => {
281 $toast.success('Simulator successfully started')
282 })
283 .catch((error: Error) => {
284 $toast.error('Error at starting simulator')
285 console.error('Error at starting simulator:', error)
286 })
240fa4da
JB
287 .finally(() => {
288 getSimulatorState()
289 })
5a010bf0 290}
fa5d129a 291const stopSimulator = (): void => {
cea23fa0
JB
292 uiClient
293 .stopSimulator()
294 .then(() => {
5c0e9352 295 if (app != null) {
7e315430 296 app.appContext.config.globalProperties.$chargingStations.value = []
5c0e9352 297 }
cea23fa0
JB
298 $toast.success('Simulator successfully stopped')
299 })
300 .catch((error: Error) => {
301 $toast.error('Error at stopping simulator')
302 console.error('Error at stopping simulator:', error)
303 })
240fa4da
JB
304 .finally(() => {
305 getSimulatorState()
306 })
5a010bf0 307}
32de5a57
LM
308</script>
309
310<style>
ca1e5439 311#charging-stations-container {
1d41bc6b 312 height: fit-content;
32de5a57 313 width: 100%;
5a010bf0 314 display: flex;
32de5a57 315 flex-direction: column;
5a010bf0
JB
316}
317
0344ad2b
JB
318#ui-server-container {
319 display: flex;
239bd875 320 justify-content: center;
754d8199 321 border-style: outset;
0344ad2b
JB
322}
323
324#ui-server-selector {
325 width: 100%;
239bd875 326 background-color: rgb(239, 239, 239);
c6308554 327 font: small-caption;
0344ad2b
JB
328 text-align: center;
329}
330
239bd875 331#ui-server-selector:hover {
bad93db3 332 background-color: rgb(229, 229, 229);
239bd875
JB
333}
334
13c19b7b
JB
335#buttons-container {
336 display: flex;
337 flex-direction: row;
338}
339
6027002f 340.simulator-start-button {
3802683b
JB
341 color: ivory;
342 background-color: green;
343}
344
fec03138 345.simulator-start-button:hover {
fec03138
JB
346 background-color: rgb(0, 98, 0);
347}
348
6027002f 349.simulator-stop-button {
3802683b
JB
350 color: ivory;
351 background-color: red;
352}
353
fec03138
JB
354.simulator-stop-button:hover {
355 background-color: rgb(225, 0, 0);
356}
357
14ee627a
JB
358#action-button {
359 flex: none;
878855a2
JB
360}
361
32de5a57 362#reload-button {
3802683b 363 color: ivory;
9dc8b66f 364 background-color: blue;
c6308554 365 font-size: 2rem;
32de5a57
LM
366}
367
368#reload-button:hover {
9dc8b66f 369 background-color: rgb(0, 0, 225);
32de5a57
LM
370}
371
372#reload-button:active {
4b10e4f9 373 background-color: darkblue;
32de5a57 374}
229d8c34
JB
375
376#action {
916f0920 377 min-width: max-content;
3802683b 378 color: ivory;
229d8c34 379 background-color: black;
916f0920 380 padding: 0.8%;
229d8c34 381}
32de5a57 382</style>