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