]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
fix(ui-web): harmonize imports, fix promise chain ordering, and remove dead code
authorJérôme Benoit <jerome.benoit@sap.com>
Thu, 30 Apr 2026 08:04:54 +0000 (10:04 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Thu, 30 Apr 2026 08:04:54 +0000 (10:04 +0200)
42 files changed:
ui/web/src/App.vue
ui/web/src/core/Constants.ts
ui/web/src/core/index.ts
ui/web/src/main.ts
ui/web/src/shared/components/SkinLoadError.vue
ui/web/src/shared/composables/index.ts [deleted file]
ui/web/src/shared/composables/useFetchData.ts
ui/web/src/shared/composables/useSkin.ts
ui/web/src/shared/composables/useStartTxForm.ts
ui/web/src/shared/utils/formatSupervisionUrl.ts
ui/web/src/skins/classic/ClassicLayout.vue
ui/web/src/skins/classic/components/actions/AddChargingStations.vue
ui/web/src/skins/classic/components/actions/SetSupervisionUrl.vue
ui/web/src/skins/classic/components/actions/StartTransaction.vue
ui/web/src/skins/classic/components/buttons/ToggleButton.vue
ui/web/src/skins/classic/components/charging-stations/CSConnector.vue
ui/web/src/skins/classic/components/charging-stations/CSData.vue
ui/web/src/skins/modern/ModernLayout.vue
ui/web/src/skins/modern/components/ConnectorRow.vue
ui/web/src/skins/modern/components/SimulatorBar.vue
ui/web/src/skins/modern/components/StationCard.vue
ui/web/src/skins/modern/components/dialogs/AddStationsDialog.vue
ui/web/src/skins/modern/components/dialogs/AuthorizeDialog.vue
ui/web/src/skins/modern/components/dialogs/SetSupervisionUrlDialog.vue
ui/web/src/skins/modern/components/dialogs/StartTransactionDialog.vue
ui/web/tests/unit/UIClient.test.ts
ui/web/tests/unit/Utils.test.ts
ui/web/tests/unit/router.test.ts
ui/web/tests/unit/shared/composables/useLayoutData.test.ts
ui/web/tests/unit/shared/composables/useSimulatorControl.test.ts
ui/web/tests/unit/skins/classic/Actions.test.ts
ui/web/tests/unit/skins/classic/CSConnector.test.ts
ui/web/tests/unit/skins/classic/CSData.test.ts
ui/web/tests/unit/skins/classic/CSTable.test.ts
ui/web/tests/unit/skins/classic/ClassicComponents.test.ts
ui/web/tests/unit/skins/classic/ClassicLayout.test.ts
ui/web/tests/unit/skins/modern/ConnectorRow.test.ts
ui/web/tests/unit/skins/modern/Dialogs.test.ts
ui/web/tests/unit/skins/modern/Errors.test.ts
ui/web/tests/unit/skins/modern/ModernLayout.test.ts
ui/web/tests/unit/skins/modern/SimulatorBar.test.ts
ui/web/tests/unit/skins/modern/StationCard.test.ts

index 5420ce0c30c2e9283a9012a710a9f0c02111f0d7..8b7476f41a5c74aeb72b298094622a68bc10b1df 100644 (file)
@@ -23,6 +23,7 @@
 <script setup lang="ts">
 import { computed, defineAsyncComponent, markRaw, watch } from 'vue'
 
+import { ASYNC_COMPONENT_DELAY_MS, ASYNC_COMPONENT_TIMEOUT_MS } from '@/core/index.js'
 import SkinLoadError from '@/shared/components/SkinLoadError.vue'
 import SkinLoading from '@/shared/components/SkinLoading.vue'
 import { useSkin } from '@/shared/composables/useSkin.js'
@@ -41,11 +42,11 @@ const skinLayoutMap = new Map(
     s.id,
     markRaw(
       defineAsyncComponent({
-        delay: 200,
+        delay: ASYNC_COMPONENT_DELAY_MS,
         errorComponent: SkinLoadError,
         loader: () => s.loadLayout(),
         loadingComponent: SkinLoading,
-        timeout: 10000,
+        timeout: ASYNC_COMPONENT_TIMEOUT_MS,
       })
     ),
   ])
index f904db63eaf83cdd545bc9550236c335ccd05123..e92023c9ec811489fc8a5c58d7a945a07129e1b0 100644 (file)
@@ -1,6 +1,11 @@
 // Local UI project constants
 
+export const ASYNC_COMPONENT_DELAY_MS = 200
+export const ASYNC_COMPONENT_TIMEOUT_MS = 10_000
 export const EMPTY_VALUE_PLACEHOLDER = 'Ø'
+export const MAX_SKIN_ERROR_RELOADS = 2
+export const MAX_STATIONS_PER_ADD = 100
+export const WH_PER_KWH = 1000
 
 export const ROUTE_NAMES = {
   ADD_CHARGING_STATIONS: 'add-charging-stations',
index 1b6e7b98eada2e939c32b42f1fb7d86c56174191..e730115f9cd3db608ba3ae9aa06e1b1f3dac2dc4 100644 (file)
@@ -1,10 +1,15 @@
 export {
+  ASYNC_COMPONENT_DELAY_MS,
+  ASYNC_COMPONENT_TIMEOUT_MS,
   EMPTY_VALUE_PLACEHOLDER,
   LEGACY_UI_SERVER_CONFIG_KEY,
+  MAX_SKIN_ERROR_RELOADS,
+  MAX_STATIONS_PER_ADD,
   ROUTE_NAMES,
   SHARED_TOGGLE_BUTTON_KEY_PREFIX,
   TOGGLE_BUTTON_KEY_PREFIX,
   UI_SERVER_CONFIGURATION_INDEX_KEY,
+  WH_PER_KWH,
 } from './Constants.js'
 export {
   chargingStationsKey,
index 48c8db14ac3883841041f2f2f24a379465b09857..164b0be1fb880b4034bd5fbb186cb6a49cf0eaf9 100644 (file)
@@ -19,7 +19,7 @@ import {
   UIClient,
   uiClientKey,
 } from '@/core/index.js'
-import { router } from '@/router'
+import { router } from '@/router/index.js'
 import { SKIN_STORAGE_KEY, useSkin } from '@/shared/composables/useSkin.js'
 import { DEFAULT_THEME, THEME_STORAGE_KEY, useTheme } from '@/shared/composables/useTheme.js'
 import { DEFAULT_SKIN } from '@/skins/registry.js'
@@ -40,8 +40,10 @@ import './assets/themes/tokyo-night-storm.css'
 const initializeApp = async (app: AppType, config: ConfigurationData): Promise<void> => {
   app.config.errorHandler = (error, instance, info) => {
     console.error('Error:', error)
-    console.info('Vue instance:', instance)
-    console.info('Error info:', info)
+    if (import.meta.env.DEV) {
+      console.info('Vue instance:', instance)
+      console.info('Error info:', info)
+    }
     // TODO: add code for UI notifications or other error handling logic
   }
 
index 60dfeea5c3098ccaa2955ee72764287624f7064e..aad032821e8dccb53b396a7905d2d743dd721d3b 100644 (file)
@@ -11,7 +11,7 @@
 </template>
 
 <script setup lang="ts">
-import { setToLocalStorage } from '@/core/index.js'
+import { MAX_SKIN_ERROR_RELOADS, setToLocalStorage } from '@/core/index.js'
 import { SKIN_STORAGE_KEY } from '@/shared/composables/useSkin.js'
 import { DEFAULT_SKIN, skins } from '@/skins/registry.js'
 
@@ -32,7 +32,7 @@ function resetToDefault (): void {
   } catch {
     // sessionStorage unavailable (e.g. Safari private browsing)
   }
-  if (count >= 2) {
+  if (count >= MAX_SKIN_ERROR_RELOADS) {
     // Stop infinite reload loop — show message instead
     return
   }
diff --git a/ui/web/src/shared/composables/index.ts b/ui/web/src/shared/composables/index.ts
deleted file mode 100644 (file)
index 85572fa..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-export { useAddStationsForm } from './useAddStationsForm.js'
-export { useAsyncAction } from './useAsyncAction.js'
-export { useConnectorActions } from './useConnectorActions.js'
-export { useFetchData } from './useFetchData.js'
-export { useLayoutData } from './useLayoutData.js'
-export { useSetUrlForm } from './useSetUrlForm.js'
-export { useSimulatorControl } from './useSimulatorControl.js'
-export { SKIN_STORAGE_KEY, useSkin } from './useSkin.js'
-export type { SkinName } from './useSkin.js'
-export { useStartTxForm } from './useStartTxForm.js'
-export { useStationActions } from './useStationActions.js'
-export { AVAILABLE_THEMES, DEFAULT_THEME, THEME_STORAGE_KEY, useTheme } from './useTheme.js'
-export type { ThemeName } from './useTheme.js'
index 118a63218644e92e3f69fecf09f703e7e6c087a0..d95871b4c218bd3aafa548ecd857c35411d5d4a3 100644 (file)
@@ -13,26 +13,28 @@ export const useFetchData = (
   const fetching = vueRef(false)
   const $toast = useToast()
   const fetch = (): void => {
-    if (!fetching.value) {
-      fetching.value = true
-      clientFn()
-        .then((response: ResponsePayload) => {
-          onSuccess(response)
-          return undefined
-        })
-        .finally(() => {
-          fetching.value = false
-        })
-        .catch((error: unknown) => {
-          try {
-            onError?.()
-          } catch (callbackError: unknown) {
-            console.error('Error in onError callback:', callbackError)
-          }
-          $toast.error(errorMsg)
-          console.error(`${errorMsg}:`, error)
-        })
+    if (fetching.value) {
+      return
     }
+    fetching.value = true
+    // eslint-disable-next-line promise/catch-or-return -- .catch() is present; .finally() at end is idiomatic
+    clientFn()
+      .then((response: ResponsePayload) => {
+        onSuccess(response)
+        return undefined
+      })
+      .catch((error: unknown) => {
+        try {
+          onError?.()
+        } catch (callbackError: unknown) {
+          console.error('Error in onError callback:', callbackError)
+        }
+        $toast.error(errorMsg)
+        console.error(`${errorMsg}:`, error)
+      })
+      .finally(() => {
+        fetching.value = false
+      })
   }
   return { fetch, fetching }
 }
index f5bc2463c085d6ee500bcc35365a8fca9d543171..47f3363db400f5dc059058472ee738d73426f2a9 100644 (file)
@@ -134,7 +134,7 @@ async function performSkinSwitch (skinId: string): Promise<boolean> {
       /* sessionStorage unavailable */
     }
     return true
-  } catch (error) {
+  } catch (error: unknown) {
     const message = error instanceof Error ? error.message : String(error)
     console.warn(`[useSkin] Failed to load CSS for skin '${skinId}':`, message)
     lastError.value = message
index c487117e86526f07769f25e8a2164e1fd90a433c..2f5615940f93d957c5934b7a6d2008804c69298f 100644 (file)
@@ -1,14 +1,14 @@
 import { convertToInt, type OCPPVersion } from 'ui-common'
-import { readonly, ref, type Ref } from 'vue'
+import { type MaybeRef, readonly, ref, type Ref, toValue } from 'vue'
 import { useToast } from 'vue-toast-notification'
 
 import { useUIClient } from '@/core/index.js'
 
 export interface StartTxFormConfig {
   connectorId: string
-  evseId?: number
+  evseId?: MaybeRef<number | undefined>
   hashId: string
-  ocppVersion?: OCPPVersion
+  ocppVersion?: MaybeRef<OCPPVersion | undefined>
   options?: {
     onCleanup?: () => void
     onError?: (error: unknown, step?: 'authorize' | 'startTransaction') => void
@@ -67,7 +67,7 @@ export function useStartTxForm (config: StartTxFormConfig): {
         }
         try {
           await $uiClient.authorize(hashId, idTag)
-        } catch (error) {
+        } catch (error: unknown) {
           $toast.error('Error at authorizing RFID tag')
           console.error('Error at authorizing RFID tag:', error)
           options?.onError?.(error, 'authorize')
@@ -79,13 +79,13 @@ export function useStartTxForm (config: StartTxFormConfig): {
       try {
         await $uiClient.startTransaction(hashId, {
           connectorId: convertToInt(connectorId),
-          evseId,
+          evseId: toValue(evseId),
           idTag,
-          ocppVersion,
+          ocppVersion: toValue(ocppVersion),
         })
         $toast.success('Transaction successfully started')
         return true
-      } catch (error) {
+      } catch (error: unknown) {
         $toast.error('Error at starting transaction')
         console.error('Error at starting transaction:', error)
         options?.onError?.(error, 'startTransaction')
index 0c9d6b99d283b357e9893b9be291dbd1804ef20c..f64d90e3152651fd256e1e11e7ee59b28c807fa8 100644 (file)
@@ -1,4 +1,4 @@
-import { EMPTY_VALUE_PLACEHOLDER } from '@/core/Constants.js'
+import { EMPTY_VALUE_PLACEHOLDER } from '@/core/index.js'
 
 export interface FormatSupervisionUrlOptions {
   /** Insert zero-width-space after dots for word-break in table cells. */
index ae91b53ef62d3a0d63b3a69915534f9a6558bb85..316bf75233978fbb5cab2a199ef13282c797836b 100644 (file)
@@ -110,7 +110,7 @@ import {
   TOGGLE_BUTTON_KEY_PREFIX,
   UI_SERVER_CONFIGURATION_INDEX_KEY,
   useChargingStations,
-} from '@/core'
+} from '@/core/index.js'
 import { useLayoutData } from '@/shared/composables/useLayoutData.js'
 import { useSimulatorControl } from '@/shared/composables/useSimulatorControl.js'
 import { useSkin } from '@/shared/composables/useSkin.js'
index 1da70e47e52f9b8b974b1c3ad66443272a589b4b..26b05c8c5d86df3189b975de2ebcc84f97eea09d 100644 (file)
@@ -25,7 +25,7 @@
     id="number-of-stations"
     v-model="formState.numberOfStations"
     class="classic-number-of-stations"
-    max="100"
+    :max="MAX_STATIONS_PER_ADD"
     min="1"
     name="number-of-stations"
     placeholder="number of stations"
 <script setup lang="ts">
 import { useRouter } from 'vue-router'
 
-import { resetToggleButtonState, ROUTE_NAMES } from '@/core'
+import { MAX_STATIONS_PER_ADD, resetToggleButtonState, ROUTE_NAMES } from '@/core/index.js'
 import { useAddStationsForm } from '@/shared/composables/useAddStationsForm.js'
 
 import Button from '../buttons/ClassicButton.vue'
index d4f7d3d5cdf0f432738aaff41724c88d63b704a2..512d3fc0963d2ea6bc6c0d2de6db89ba29faf7f1 100644 (file)
@@ -44,7 +44,7 @@
 <script setup lang="ts">
 import { useRouter } from 'vue-router'
 
-import { resetToggleButtonState, ROUTE_NAMES } from '@/core'
+import { resetToggleButtonState, ROUTE_NAMES } from '@/core/index.js'
 import { useSetUrlForm } from '@/shared/composables/useSetUrlForm.js'
 
 import Button from '../buttons/ClassicButton.vue'
index 762d39dd2ce5109adecbf3fb0989129f0e963c49..4c51be8fedfa8903f566ecbe31ef8a4459bd3631 100644 (file)
@@ -42,7 +42,7 @@ import type { OCPPVersion } from 'ui-common'
 import { computed } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 
-import { resetToggleButtonState, ROUTE_NAMES } from '@/core'
+import { resetToggleButtonState, ROUTE_NAMES } from '@/core/index.js'
 import { useStartTxForm } from '@/shared/composables/useStartTxForm.js'
 
 import Button from '../buttons/ClassicButton.vue'
@@ -70,9 +70,9 @@ const toggleButtonId = computed(
 
 const { formState, submitForm } = useStartTxForm({
   connectorId: props.connectorId,
-  evseId: evseId.value,
+  evseId,
   hashId: props.hashId,
-  ocppVersion: ocppVersion.value,
+  ocppVersion,
   options: {
     onCleanup: () => {
       resetToggleButtonState(toggleButtonId.value, true)
index ecc38b1c6f7bc537e72cdc53e7af0f146acf74a4..123b11d75d0270ddbe35c1c0ae5022c7663c8152 100644 (file)
@@ -16,7 +16,7 @@ import {
   setToLocalStorage,
   SHARED_TOGGLE_BUTTON_KEY_PREFIX,
   TOGGLE_BUTTON_KEY_PREFIX,
-} from '@/core'
+} from '@/core/index.js'
 
 import Button from './ClassicButton.vue'
 
index 7f33f735c1a7b15ccaffd62b56a54eba57e8d3d1..fe5df88aabc7c9ddc9ccd94100d2685359fa0a5c 100644 (file)
@@ -71,7 +71,7 @@ import type { ConnectorStatus, OCPPVersion, Status } from 'ui-common'
 import { computed } from 'vue'
 import { useRouter } from 'vue-router'
 
-import { EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES } from '@/core'
+import { EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES } from '@/core/index.js'
 import { useConnectorActions } from '@/shared/composables/useConnectorActions.js'
 
 import Button from '../buttons/ClassicButton.vue'
index 0eea87c56473659491df0334cd7a3e25b4029cfd..e83841123429bb45a32f6bc42bd454a74741b39b 100644 (file)
@@ -125,7 +125,11 @@ import {
 } from 'ui-common'
 import { computed } from 'vue'
 
-import { deleteLocalStorageByKeyPattern, EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES } from '@/core'
+import {
+  deleteLocalStorageByKeyPattern,
+  EMPTY_VALUE_PLACEHOLDER,
+  ROUTE_NAMES,
+} from '@/core/index.js'
 import { useStationActions } from '@/shared/composables/useStationActions.js'
 import { formatSupervisionUrl } from '@/shared/utils/formatSupervisionUrl.js'
 import { getATGStatus, getConnectorEntries } from '@/shared/utils/stationStatus.js'
index fc7f2b3b0bbc72d48b1627d5aa1801a9e6fac50d..0fce3967837814b89994d1c08a5878c1ddca4140 100644 (file)
@@ -1,14 +1,12 @@
 <template>
   <main class="modern-app">
     <SimulatorBar
-      :refresh-pending="loading"
       :selected-server-index="uiServerIndex"
       :server-switch-pending="serverSwitchPending"
       :simulator-pending="simulatorPending"
       :simulator-state="simulatorState"
       :ui-server-configurations="uiServerConfigurations"
       @add="showAddDialog = true"
-      @refresh="getData"
       @switch-server="handleUIServerChange"
       @toggle-simulator="toggleSimulator"
     />
 import { type OCPPVersion } from 'ui-common'
 import { defineAsyncComponent, ref } from 'vue'
 
-import { getFromLocalStorage, UI_SERVER_CONFIGURATION_INDEX_KEY, useChargingStations } from '@/core'
+import {
+  ASYNC_COMPONENT_DELAY_MS,
+  ASYNC_COMPONENT_TIMEOUT_MS,
+  getFromLocalStorage,
+  UI_SERVER_CONFIGURATION_INDEX_KEY,
+  useChargingStations,
+} from '@/core/index.js'
 import SkinLoadError from '@/shared/components/SkinLoadError.vue'
 import SkinLoading from '@/shared/components/SkinLoading.vue'
 import { useLayoutData } from '@/shared/composables/useLayoutData.js'
@@ -96,11 +100,11 @@ import ConfirmDialog from './components/ConfirmDialog.vue'
  */
 function defineAsyncDialog (loader: () => Promise<{ default: unknown }>) {
   return defineAsyncComponent({
-    delay: 200,
+    delay: ASYNC_COMPONENT_DELAY_MS,
     errorComponent: SkinLoadError,
     loader: loader as () => Promise<{ default: import('vue').Component }>,
     loadingComponent: SkinLoading,
-    timeout: 10000,
+    timeout: ASYNC_COMPONENT_TIMEOUT_MS,
   })
 }
 
@@ -120,7 +124,7 @@ import StationCard from './components/StationCard.vue'
 const $chargingStations = useChargingStations()
 
 const layoutData = useLayoutData()
-const { getChargingStations, getData, loading, simulatorState, uiServerConfigurations } = layoutData
+const { getChargingStations, simulatorState, uiServerConfigurations } = layoutData
 
 const uiServerIndex = ref(getFromLocalStorage<number>(UI_SERVER_CONFIGURATION_INDEX_KEY, 0))
 
index 6722f077f020297cc9f5e5c213d528a212d56903..abfa8b9481781e2fadbf0ecd02fde030290a4257 100644 (file)
@@ -152,6 +152,7 @@ import type { ConnectorStatus, OCPPVersion, Status } from 'ui-common'
 
 import { computed } from 'vue'
 
+import { WH_PER_KWH } from '@/core/index.js'
 import { useConnectorActions } from '@/shared/composables/useConnectorActions.js'
 import { getConnectorStatusVariant } from '@/shared/utils/stationStatus.js'
 
@@ -213,7 +214,7 @@ const lockTitle = computed(() => {
 const txEnergy = computed(() => {
   const wh = props.connector.transactionEnergyActiveImportRegisterValue
   if (wh == null) return '—'
-  if (wh >= 1000) return `${(wh / 1000).toFixed(2)} kWh`
+  if (wh >= WH_PER_KWH) return `${(wh / WH_PER_KWH).toFixed(2)} kWh`
   return `${Math.round(wh)} Wh`
 })
 
index 336ff83450ac1364e682234012399e17fd0de4a9..7f18761440e1777043c9289ba7fa366f8c224c72 100644 (file)
       </select>
     </div>
     <div class="modern-bar__group">
-      <!-- <ActionButton
-        variant="ghost"
-        :pending="refreshPending"
-        title="Refresh charging stations"
-        @click="$emit('refresh')"
-      >
-        Refresh
-      </ActionButton> -->
       <ActionButton
         variant="primary"
         @click="$emit('add')"
@@ -114,7 +106,6 @@ function getSelectIndex (e: Event): number {
 }
 
 const props = defineProps<{
-  refreshPending?: boolean
   selectedServerIndex: number
   serverSwitchPending?: boolean
   simulatorPending?: boolean
@@ -124,7 +115,6 @@ const props = defineProps<{
 
 defineEmits<{
   add: []
-  refresh: []
   'switch-server': [index: number]
   'toggle-simulator': []
 }>()
index fe0665e3103a6978c99e5134e67b19fa971d5865..3d056eb7459bcaec0872ab3d27f13cc5703ac2b4 100644 (file)
@@ -168,7 +168,7 @@ import {
 } from 'ui-common'
 import { computed, ref } from 'vue'
 
-import { deleteLocalStorageByKeyPattern, EMPTY_VALUE_PLACEHOLDER as EMPTY } from '@/core'
+import { deleteLocalStorageByKeyPattern, EMPTY_VALUE_PLACEHOLDER as EMPTY } from '@/core/index.js'
 import { useStationActions } from '@/shared/composables/useStationActions.js'
 import { formatSupervisionUrl } from '@/shared/utils/formatSupervisionUrl.js'
 import {
index 718f72afbeec11e486095650d34c2f6eac03e308..4c4a6a4e57982726ee204ea43e8ff4774429ef1d 100644 (file)
@@ -42,7 +42,7 @@
           id="modern-add-count"
           v-model.number="formState.numberOfStations"
           class="modern-form__input"
-          max="100"
+          :max="MAX_STATIONS_PER_ADD"
           min="1"
           type="number"
           required
 </template>
 
 <script setup lang="ts">
+import { MAX_STATIONS_PER_ADD } from '@/core/index.js'
 import { useAddStationsForm } from '@/shared/composables/useAddStationsForm.js'
 
 import ActionButton from '../ActionButton.vue'
index aa8ae6bac224fadd25b42b84745cf4ab7f4e0545..61e8d3c8c25b3702a7e0bdc3dfe3cf47ba8ef7c0 100644 (file)
@@ -63,7 +63,7 @@
 import { computed, ref } from 'vue'
 import { useToast } from 'vue-toast-notification'
 
-import { useUIClient } from '@/core'
+import { useUIClient } from '@/core/index.js'
 
 import { type FailureInfo, getFailureInfo } from '../../utils/errors.js'
 import ActionButton from '../ActionButton.vue'
@@ -104,7 +104,7 @@ const submit = async (): Promise<void> => {
     await $uiClient.authorize(props.hashId, idTag.value)
     $toast.success(`Authorized ${idTag.value}`)
     close()
-  } catch (error) {
+  } catch (error: unknown) {
     console.error('Error authorizing:', error)
     const info = getFailureInfo(error)
     lastFailure.value = info
index 0689f786024c47675efae00364b77a19074b5a20..d57764d92760007ae7ff7150947f0c023962bb91 100644 (file)
@@ -83,7 +83,7 @@
 <script setup lang="ts">
 import { computed, ref, watch } from 'vue'
 
-import { useChargingStations, useUIClient } from '@/core'
+import { useChargingStations, useUIClient } from '@/core/index.js'
 import { useSetUrlForm } from '@/shared/composables/useSetUrlForm.js'
 import { stripStationId } from '@/shared/utils/stripStationId.js'
 
index 0ec8afb428ecb23d31df5b9e632802722c9540eb..95dc8ea520e9a8dd5555c317528684d087452d80 100644 (file)
@@ -78,7 +78,7 @@ import { computed, ref, watch } from 'vue'
 
 import { useStartTxForm } from '@/shared/composables/useStartTxForm.js'
 
-import { type FailureInfo, getFailureInfo } from '../../utils/errors'
+import { type FailureInfo, getFailureInfo } from '../../utils/errors.js'
 import ActionButton from '../ActionButton.vue'
 import Modal from '../ModernModal.vue'
 
index b2b7d4ef9472d6bf0423c9846bbfe7fe3670fe4b..fc1e8d69ba9e04affa8640458989367a101bb27c 100644 (file)
@@ -14,7 +14,7 @@ import {
 } from 'ui-common'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
-import { UIClient } from '@/core'
+import { UIClient } from '@/core/index.js'
 
 import { toastMock } from '../setup'
 import { createUIServerConfig, TEST_HASH_ID, TEST_ID_TAG } from './constants'
index 566a3bc02783aeb2690fd9f901cfcead6f7188c4..602a7818962cb6deea732fea9983135db52767b9 100644 (file)
@@ -15,7 +15,7 @@ import {
   useChargingStations,
   useConfiguration,
   useTemplates,
-} from '@/core'
+} from '@/core/index.js'
 import { useFetchData } from '@/shared/composables/useFetchData.js'
 
 import { toastMock } from '../setup'
index 52a440a6f1a3ce3f08a3ce21909f2a8d6a55f97e..7c34806aad823304fb8fff5d57fe5a308d673778 100644 (file)
@@ -4,7 +4,7 @@
  */
 import { describe, expect, it, vi } from 'vitest'
 
-import { ROUTE_NAMES } from '@/core'
+import { ROUTE_NAMES } from '@/core/index.js'
 import { router } from '@/router/index.js'
 
 vi.mock('@/shared/composables/useSkin.js', async importOriginal => {
index 688bf39b4d32ce0fe7e0823217148c2546a240ea..460816ecf6d6c1d5287a36e6970543ca05f4b4c6 100644 (file)
@@ -8,9 +8,9 @@ import { flushPromises } from '@vue/test-utils'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { type Ref, ref } from 'vue'
 
-import { useChargingStations, useConfiguration, useTemplates, useUIClient } from '@/core'
+import { useChargingStations, useConfiguration, useTemplates, useUIClient } from '@/core/index.js'
 
-vi.mock('@/core', async importOriginal => {
+vi.mock('@/core/index.js', async importOriginal => {
   const actual = await importOriginal()
   return {
     ...(actual as Record<string, unknown>),
index c408263b086f8f6937cb19309bf654f3120f8673..b20edb59deee956970838477ff2aa0bd8f863805 100644 (file)
@@ -15,13 +15,13 @@ import {
   useChargingStations,
   useConfiguration,
   useUIClient,
-} from '@/core'
+} from '@/core/index.js'
 
 import { toastMock } from '../../../setup.js'
 import { createUIServerConfig } from '../../constants'
 import { createMockUIClient, type MockUIClient, withSetup } from '../../helpers.js'
 
-vi.mock('@/core', async importOriginal => {
+vi.mock('@/core/index.js', async importOriginal => {
   const actual = await importOriginal()
   return {
     ...(actual as Record<string, unknown>),
index 883f9da4d9cb3e0a7521fb5d099d0183f87e7c8c..97f92cb09fa156c129b949f56b4e396cd0a2176a 100644 (file)
@@ -6,7 +6,7 @@ import { flushPromises, mount } from '@vue/test-utils'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { ref, shallowRef } from 'vue'
 
-import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core'
+import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core/index.js'
 import AddChargingStations from '@/skins/classic/components/actions/AddChargingStations.vue'
 import SetSupervisionUrl from '@/skins/classic/components/actions/SetSupervisionUrl.vue'
 import StartTransaction from '@/skins/classic/components/actions/StartTransaction.vue'
index a2efabf5054a3b76075050171284e4a10d76affc..0596e3c3b567eaa52cc0164679b33b57f71b1093 100644 (file)
@@ -6,7 +6,7 @@ import { flushPromises, mount } from '@vue/test-utils'
 import { type ConnectorStatus, OCPP16ChargePointStatus, OCPPVersion } from 'ui-common'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
-import { uiClientKey } from '@/core'
+import { uiClientKey } from '@/core/index.js'
 import CSConnector from '@/skins/classic/components/charging-stations/CSConnector.vue'
 
 import { toastMock } from '../../../setup.js'
index 4de141ee6b2814793783d51b2ff0249edd6d4104..f6279be504c95e3a8849924ce85e421f6f920693 100644 (file)
@@ -6,7 +6,7 @@ import { flushPromises, mount } from '@vue/test-utils'
 import { type ChargingStationData, OCPP16AvailabilityType, OCPPVersion } from 'ui-common'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
-import { uiClientKey } from '@/core'
+import { uiClientKey } from '@/core/index.js'
 import CSData from '@/skins/classic/components/charging-stations/CSData.vue'
 
 import { toastMock } from '../../../setup.js'
index 1dfe9346f7c024ac04eddcb89821e317f61ce5ff..511326e7350a462a8441c857df9ce6f809a75b67 100644 (file)
@@ -5,7 +5,7 @@
 import { shallowMount } from '@vue/test-utils'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
-import { uiClientKey } from '@/core'
+import { uiClientKey } from '@/core/index.js'
 import CSTable from '@/skins/classic/components/charging-stations/CSTable.vue'
 
 import { createChargingStationData } from '../../constants.js'
index 1f1649432a524b829e86a16e0a7087b5e7e75134..305dfb92227a30a8607a68b10096f49c22a0dcd7 100644 (file)
@@ -8,7 +8,7 @@ import { flushPromises, mount } from '@vue/test-utils'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { defineComponent, shallowRef } from 'vue'
 
-import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core'
+import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core/index.js'
 import ToggleButton from '@/skins/classic/components/buttons/ToggleButton.vue'
 import CSTable from '@/skins/classic/components/charging-stations/CSTable.vue'
 
index b745e6dc329f8ebc10dc4f169e18bbf50344ee9b..86e2e8402ca9bf458f79979494617f27f953358c 100644 (file)
@@ -6,7 +6,7 @@ import { flushPromises, mount } from '@vue/test-utils'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { ref } from 'vue'
 
-import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core'
+import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core/index.js'
 import ClassicLayout from '@/skins/classic/ClassicLayout.vue'
 
 import { createUIServerConfig } from '../../constants'
index 93f5e267d4eb3cd733cdbef72d04250eb41a81cd..55bdecd1889b3c87408185386094b832aaaf76df 100644 (file)
@@ -11,7 +11,7 @@ import {
 } from 'ui-common'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
-import { uiClientKey } from '@/core'
+import { uiClientKey } from '@/core/index.js'
 import ConnectorRow from '@/skins/modern/components/ConnectorRow.vue'
 
 import { toastMock } from '../../../setup.js'
index 9d8d00be0405ddf1ebddc5e93dcc277586df13cb..feaec003dc8d01b15361b49752a2a3bc18da35c1 100644 (file)
@@ -8,7 +8,7 @@ import { ResponseStatus, ServerFailureError } from 'ui-common'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 import { defineComponent, ref } from 'vue'
 
-import { chargingStationsKey, templatesKey, uiClientKey } from '@/core'
+import { chargingStationsKey, templatesKey, uiClientKey } from '@/core/index.js'
 
 // Mock Modal to render slots inline (no Teleport), so `wrapper.find()` works.
 vi.mock('@/skins/modern/components/ModernModal.vue', () => ({
index e223b0866bd3b69de3ebefb1f61bf9990f3c6a0a..266db3579b2c7edc343648f008ca51806e0f8b35 100644 (file)
@@ -7,7 +7,7 @@
 import { type ResponsePayload, ResponseStatus, ServerFailureError } from 'ui-common'
 import { describe, expect, it } from 'vitest'
 
-import { getFailureInfo } from '@/skins/modern/utils/errors'
+import { getFailureInfo } from '@/skins/modern/utils/errors.js'
 
 /**
  * Builds a ResponsePayload-shaped object with custom responsesFailed entries.
index 015fa0726e9820ac0a7cbca9aa10137ef0f8db2c..ddb0006fe82e2d2774241bb7c806ea97b17e1c49 100644 (file)
@@ -14,14 +14,14 @@ import {
   UI_SERVER_CONFIGURATION_INDEX_KEY,
   uiClientKey,
   useUIClient,
-} from '@/core'
+} from '@/core/index.js'
 import ModernLayout from '@/skins/modern/ModernLayout.vue'
 
 import { toastMock } from '../../../setup.js'
 import { createChargingStationData, createUIServerConfig } from '../../constants'
 import { createMockUIClient, type MockUIClient } from '../../helpers.js'
 
-vi.mock('@/core', async importOriginal => {
+vi.mock('@/core/index.js', async importOriginal => {
   const actual = await importOriginal()
   return { ...(actual as Record<string, unknown>), useUIClient: vi.fn() }
 })
@@ -78,16 +78,14 @@ function mountView (
         },
         SetSupervisionUrlDialog: true,
         SimulatorBar: {
-          emits: ['add', 'refresh', 'switch-server', 'toggle-simulator'],
+          emits: ['add', 'switch-server', 'toggle-simulator'],
           props: [
-            'refreshPending',
             'selectedServerIndex',
             'simulatorPending',
             'simulatorState',
             'uiServerConfigurations',
           ],
           template: `<div class="stub-sim-bar">
-            <button class="stub-refresh" @click="$emit('refresh')">r</button>
             <button class="stub-add" @click="$emit('add')">+</button>
             <button class="stub-toggle" @click="$emit('toggle-simulator')">t</button>
             <button class="stub-switch" @click="$emit('switch-server', 1)">s</button>
@@ -186,7 +184,7 @@ describe('ModernLayout', () => {
     })
     const wrapper = mountView()
     await flushPromises()
-    await wrapper.find('.stub-refresh').trigger('click')
+    getWSHandler('open')?.()
     await flushPromises()
     await wrapper.find('.stub-toggle').trigger('click')
     await flushPromises()
@@ -200,7 +198,7 @@ describe('ModernLayout', () => {
     })
     const wrapper = mountView()
     await flushPromises()
-    await wrapper.find('.stub-refresh').trigger('click')
+    getWSHandler('open')?.()
     await flushPromises()
     await wrapper.find('.stub-toggle').trigger('click')
     await flushPromises()
@@ -217,7 +215,7 @@ describe('ModernLayout', () => {
     })
     const wrapper = mountView()
     await flushPromises()
-    await wrapper.find('.stub-refresh').trigger('click')
+    getWSHandler('open')?.()
     await flushPromises()
     await wrapper.find('.stub-toggle').trigger('click')
     await flushPromises()
@@ -234,7 +232,7 @@ describe('ModernLayout', () => {
     })
     const wrapper = mountView()
     await flushPromises()
-    await wrapper.find('.stub-refresh').trigger('click')
+    getWSHandler('open')?.()
     await flushPromises()
     await wrapper.find('.stub-toggle').trigger('click')
     await flushPromises()
@@ -249,7 +247,7 @@ describe('ModernLayout', () => {
     mockClient.startSimulator = vi.fn().mockRejectedValue(new Error('x'))
     const wrapper = mountView()
     await flushPromises()
-    await wrapper.find('.stub-refresh').trigger('click')
+    getWSHandler('open')?.()
     await flushPromises()
     await wrapper.find('.stub-toggle').trigger('click')
     await flushPromises()
index 7619eaf23fd5665af4ca71b650cb429561972bc3..c9806a906ed1f4764c1274f17a5f553257667798 100644 (file)
@@ -74,13 +74,6 @@ describe('SimulatorBar', () => {
     expect(wrapper.emitted('switch-server')).toEqual([[1]])
   })
 
-  // it('should emit refresh when refresh button is clicked', async () => {
-  //   const wrapper = mountBar()
-  //   const [refreshBtn] = wrapper.findAll('.modern-btn')
-  //   await refreshBtn.trigger('click')
-  //   expect(wrapper.emitted('refresh')).toHaveLength(1)
-  // })
-
   it('should emit add when add-stations button is clicked', async () => {
     const wrapper = mountBar()
     const buttons = wrapper.findAll('.modern-btn')
index de7a083dc66c27c30e7dc1573acae0fffbd04cbb..15072b74a52fbc9f78560e25ae26012fa7764168 100644 (file)
@@ -6,7 +6,7 @@ import { flushPromises, mount } from '@vue/test-utils'
 import { type ChargingStationData, OCPP16AvailabilityType } from 'ui-common'
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
-import { uiClientKey } from '@/core'
+import { uiClientKey } from '@/core/index.js'
 import StationCard from '@/skins/modern/components/StationCard.vue'
 
 import { toastMock } from '../../../setup.js'