fix(ui): ensure templates are refreshed at UI server change
[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 delete app?.appContext.config.globalProperties.$templates
24 },
25 { once: true }
26 )
27 app?.appContext.config.globalProperties.$uiClient.registerWSEventListener(
28 'error',
29 () => {
30 state.uiServerIndex = getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
31 app?.appContext.config.globalProperties.$uiClient.setConfiguration(
32 app?.appContext.config.globalProperties.$configuration.uiServer[
33 getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
34 ]
35 )
36 initializeWSEventListeners()
37 },
38 { once: true }
39 )
40 }
41 }
42 "
43 >
44 <option
45 v-for="uiServerConfiguration in uiServerConfigurations"
46 :value="uiServerConfiguration.index"
47 >
48 {{ uiServerConfiguration.configuration.name ?? uiServerConfiguration.configuration.host }}
49 </option>
50 </select>
51 </Container>
52 <Container id="buttons-container">
53 <Button @click="startSimulator()">Start Simulator</Button>
54 <Button @click="stopSimulator()">Stop Simulator</Button>
55 <Button @click="$router.push({ name: 'add-charging-stations' })">
56 Add Charging Stations
57 </Button>
58 <ReloadButton
59 id="reload-button"
60 :loading="state.loading"
61 @click="loadChargingStations(() => (state.renderChargingStationsList = randomUUID()))"
62 />
63 </Container>
64 <CSTable
65 v-show="
66 Array.isArray(app?.appContext.config.globalProperties.$chargingStations) &&
67 app?.appContext.config.globalProperties.$chargingStations.length > 0
68 "
69 :key="state.renderChargingStationsList"
70 :charging-stations="app?.appContext.config.globalProperties.$chargingStations"
71 />
72 </Container>
73 </template>
74
75 <script setup lang="ts">
76 import { getCurrentInstance, onMounted, reactive } from 'vue'
77 import { useToast } from 'vue-toast-notification'
78 import CSTable from '@/components/charging-stations/CSTable.vue'
79 import type { ResponsePayload, UIServerConfigurationSection } from '@/types'
80 import Container from '@/components/Container.vue'
81 import ReloadButton from '@/components/buttons/ReloadButton.vue'
82 import Button from '@/components/buttons/Button.vue'
83 import { getFromLocalStorage, setToLocalStorage } from '@/composables'
84
85 const randomUUID = (): `${string}-${string}-${string}-${string}-${string}` => {
86 return crypto.randomUUID()
87 }
88
89 const app = getCurrentInstance()
90
91 const initializeWSEventListeners = () => {
92 app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('open', () => {
93 loadChargingStations(() => (state.renderChargingStationsList = randomUUID()))
94 })
95 app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('error', () => {
96 app.appContext.config.globalProperties.$chargingStations = []
97 state.renderChargingStationsList = randomUUID()
98 })
99 app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('close', () => {
100 app.appContext.config.globalProperties.$chargingStations = []
101 state.renderChargingStationsList = randomUUID()
102 })
103 }
104
105 onMounted(() => {
106 initializeWSEventListeners()
107 })
108
109 const state = reactive({
110 renderChargingStationsList: randomUUID(),
111 loading: false,
112 uiServerIndex: getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
113 })
114
115 const uiClient = app?.appContext.config.globalProperties.$uiClient
116 const uiServerConfigurations: { configuration: UIServerConfigurationSection; index: number }[] =
117 app?.appContext.config.globalProperties.$configuration.uiServer.map(
118 (configuration: UIServerConfigurationSection, index: number) => ({
119 configuration,
120 index
121 })
122 )
123
124 const $toast = useToast()
125
126 const loadChargingStations = (renderCallback?: () => void): void => {
127 if (state.loading === false) {
128 state.loading = true
129 uiClient
130 .listChargingStations()
131 .then((response: ResponsePayload) => {
132 if (app != null) {
133 app.appContext.config.globalProperties.$chargingStations = response.chargingStations
134 }
135 })
136 .catch((error: Error) => {
137 if (app != null) {
138 app.appContext.config.globalProperties.$chargingStations = []
139 }
140 $toast.error('Error at fetching charging stations')
141 console.error('Error at fetching charging stations:', error)
142 })
143 .finally(() => {
144 if (renderCallback != null) {
145 renderCallback()
146 }
147 state.loading = false
148 })
149 }
150 }
151
152 const startSimulator = (): void => {
153 uiClient
154 .startSimulator()
155 .then(() => {
156 $toast.success('Simulator successfully started')
157 })
158 .catch((error: Error) => {
159 $toast.error('Error at starting simulator')
160 console.error('Error at starting simulator:', error)
161 })
162 }
163 const stopSimulator = (): void => {
164 uiClient
165 .stopSimulator()
166 .then(() => {
167 if (app != null) {
168 app.appContext.config.globalProperties.$chargingStations = []
169 }
170 $toast.success('Simulator successfully stopped')
171 })
172 .catch((error: Error) => {
173 $toast.error('Error at stopping simulator')
174 console.error('Error at stopping simulator:', error)
175 })
176 }
177 </script>
178
179 <style>
180 #charging-stations-container {
181 height: fit-content;
182 width: 100%;
183 display: flex;
184 flex-direction: column;
185 }
186
187 #ui-server-container {
188 display: flex;
189 flex-direction: row;
190 }
191
192 #ui-server-selector {
193 width: 100%;
194 text-align: center;
195 }
196
197 #buttons-container {
198 display: flex;
199 flex-direction: row;
200 }
201
202 #action-button {
203 flex: none;
204 }
205
206 #reload-button {
207 flex: auto;
208 color: white;
209 background-color: blue;
210 font-size: 1.5rem;
211 font-weight: bold;
212 align-items: center;
213 justify-content: center;
214 }
215
216 #reload-button:hover {
217 background-color: rgb(0, 0, 225);
218 }
219
220 #reload-button:active {
221 background-color: red;
222 }
223
224 #action {
225 color: white;
226 background-color: black;
227 padding: 1%;
228 }
229 </style>