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