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