+++ /dev/null
-import type { ChargingStationData, ConfigurationData, ResponsePayload } from 'ui-common'
-import type { InjectionKey, Ref } from 'vue'
-
-import { inject, ref as vueRef } from 'vue'
-import { useToast } from 'vue-toast-notification'
-
-import { SHARED_TOGGLE_BUTTON_KEY_PREFIX, TOGGLE_BUTTON_KEY_PREFIX } from './Constants.js'
-import { UIClient } from './UIClient.js'
-
-export const configurationKey: InjectionKey<Ref<ConfigurationData>> = Symbol('configuration')
-export const chargingStationsKey: InjectionKey<Ref<ChargingStationData[]>> =
- Symbol('chargingStations')
-export const templatesKey: InjectionKey<Ref<string[]>> = Symbol('templates')
-export const uiClientKey: InjectionKey<UIClient> = Symbol('uiClient')
-
-export const getFromLocalStorage = <T>(key: string, defaultValue: T): T => {
- try {
- const item = localStorage.getItem(key)
- return item != null ? (JSON.parse(item) as T) : defaultValue
- } catch {
- if (import.meta.env.DEV) {
- console.debug(`[localStorage] Failed to read key '${key}', using default`)
- }
- return defaultValue
- }
-}
-
-// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
-export const setToLocalStorage = <T>(key: string, value: T): void => {
- try {
- localStorage.setItem(key, JSON.stringify(value))
- } catch {
- // localStorage.setItem() can throw:
- // - QuotaExceededError when the origin's storage quota is genuinely exceeded
- // - SecurityError when storage is blocked by user settings or browser policies
- // (e.g., "Block All Cookies" in Safari, third-party iframe in Chrome, file: URLs)
- if (import.meta.env.DEV) {
- console.debug(`[localStorage] Failed to write key '${key}'`)
- }
- }
-}
-
-export const deleteFromLocalStorage = (key: string): void => {
- try {
- localStorage.removeItem(key)
- } catch {
- if (import.meta.env.DEV) {
- console.debug(`[localStorage] Failed to delete key '${key}'`)
- }
- }
-}
-
-export const getLocalStorage = (): Storage => {
- try {
- return localStorage
- } catch {
- throw new Error('localStorage is not available')
- }
-}
-
-/**
- * Deletes all localStorage entries whose key includes the given pattern.
- * @param pattern - Substring to match against localStorage keys
- */
-export const deleteLocalStorageByKeyPattern = (pattern: string): void => {
- try {
- const keysToDelete = Object.keys(localStorage).filter(key => key.includes(pattern))
- for (const key of keysToDelete) {
- deleteFromLocalStorage(key)
- }
- } catch {
- if (import.meta.env.DEV) {
- console.debug(`[localStorage] Failed to delete keys matching '${pattern}'`)
- }
- }
-}
-
-/**
- * Resets the state of a toggle button by removing its entry from localStorage.
- * @param id - The identifier of the toggle button
- * @param shared - Whether the toggle button is shared
- */
-export const resetToggleButtonState = (id: string, shared = false): void => {
- const key = shared
- ? `${SHARED_TOGGLE_BUTTON_KEY_PREFIX}${id}`
- : `${TOGGLE_BUTTON_KEY_PREFIX}${id}`
- deleteFromLocalStorage(key)
-}
-
-export const useUIClient = (): UIClient => {
- const injected = inject(uiClientKey, undefined)
- if (injected != null) return injected
- if (import.meta.env.DEV) {
- console.debug('[useUIClient] Accessed outside provide scope — using singleton fallback')
- }
- return UIClient.getInstance()
-}
-
-export const useConfiguration = (): Ref<ConfigurationData> => {
- const injected = inject(configurationKey, undefined)
- if (injected != null) return injected
- throw new Error('configuration not provided')
-}
-
-export const useChargingStations = (): Ref<ChargingStationData[]> => {
- const injected = inject(chargingStationsKey, undefined)
- if (injected != null) return injected
- throw new Error('chargingStations not provided')
-}
-
-export const useTemplates = (): Ref<string[]> => {
- const injected = inject(templatesKey, undefined)
- if (injected != null) return injected
- throw new Error('templates not provided')
-}
-
-export const useFetchData = (
- clientFn: () => Promise<ResponsePayload>,
- onSuccess: (response: ResponsePayload) => void,
- errorMsg: string,
- onError?: () => void
-): { fetch: () => void; fetching: Ref<boolean> } => {
- 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)
- })
- }
- }
- return { fetch, fetching }
-}
TOGGLE_BUTTON_KEY_PREFIX,
UI_SERVER_CONFIGURATION_INDEX_KEY,
} from './Constants.js'
-export { UIClient } from './UIClient.js'
export {
chargingStationsKey,
configurationKey,
- deleteFromLocalStorage,
- deleteLocalStorageByKeyPattern,
- getFromLocalStorage,
- getLocalStorage,
- resetToggleButtonState,
- setToLocalStorage,
templatesKey,
uiClientKey,
useChargingStations,
useConfiguration,
- useFetchData,
useTemplates,
useUIClient,
-} from './Utils.js'
+} from './providers.js'
+export {
+ deleteFromLocalStorage,
+ deleteLocalStorageByKeyPattern,
+ getFromLocalStorage,
+ getLocalStorage,
+ resetToggleButtonState,
+ setToLocalStorage,
+} from './storage.js'
+export { UIClient } from './UIClient.js'
--- /dev/null
+import type { ChargingStationData, ConfigurationData } from 'ui-common'
+import type { InjectionKey, Ref } from 'vue'
+
+import { inject } from 'vue'
+
+import { UIClient } from './UIClient.js'
+
+export const configurationKey: InjectionKey<Ref<ConfigurationData>> = Symbol('configuration')
+export const chargingStationsKey: InjectionKey<Ref<ChargingStationData[]>> =
+ Symbol('chargingStations')
+export const templatesKey: InjectionKey<Ref<string[]>> = Symbol('templates')
+export const uiClientKey: InjectionKey<UIClient> = Symbol('uiClient')
+
+export const useUIClient = (): UIClient => {
+ const injected = inject(uiClientKey, undefined)
+ if (injected != null) return injected
+ if (import.meta.env.DEV) {
+ console.debug('[useUIClient] Accessed outside provide scope — using singleton fallback')
+ }
+ return UIClient.getInstance()
+}
+
+export const useConfiguration = (): Ref<ConfigurationData> => {
+ const injected = inject(configurationKey, undefined)
+ if (injected != null) return injected
+ throw new Error('configuration not provided')
+}
+
+export const useChargingStations = (): Ref<ChargingStationData[]> => {
+ const injected = inject(chargingStationsKey, undefined)
+ if (injected != null) return injected
+ throw new Error('chargingStations not provided')
+}
+
+export const useTemplates = (): Ref<string[]> => {
+ const injected = inject(templatesKey, undefined)
+ if (injected != null) return injected
+ throw new Error('templates not provided')
+}
--- /dev/null
+import { SHARED_TOGGLE_BUTTON_KEY_PREFIX, TOGGLE_BUTTON_KEY_PREFIX } from './Constants.js'
+
+export const getFromLocalStorage = <T>(key: string, defaultValue: T): T => {
+ try {
+ const item = localStorage.getItem(key)
+ return item != null ? (JSON.parse(item) as T) : defaultValue
+ } catch {
+ if (import.meta.env.DEV) {
+ console.debug(`[localStorage] Failed to read key '${key}', using default`)
+ }
+ return defaultValue
+ }
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
+export const setToLocalStorage = <T>(key: string, value: T): void => {
+ try {
+ localStorage.setItem(key, JSON.stringify(value))
+ } catch {
+ // localStorage.setItem() can throw:
+ // - QuotaExceededError when the origin's storage quota is genuinely exceeded
+ // - SecurityError when storage is blocked by user settings or browser policies
+ // (e.g., "Block All Cookies" in Safari, third-party iframe in Chrome, file: URLs)
+ if (import.meta.env.DEV) {
+ console.debug(`[localStorage] Failed to write key '${key}'`)
+ }
+ }
+}
+
+export const deleteFromLocalStorage = (key: string): void => {
+ try {
+ localStorage.removeItem(key)
+ } catch {
+ if (import.meta.env.DEV) {
+ console.debug(`[localStorage] Failed to delete key '${key}'`)
+ }
+ }
+}
+
+export const getLocalStorage = (): Storage => {
+ try {
+ return localStorage
+ } catch {
+ throw new Error('localStorage is not available')
+ }
+}
+
+/**
+ * Deletes all localStorage entries whose key includes the given pattern.
+ * @param pattern - Substring to match against localStorage keys
+ */
+export const deleteLocalStorageByKeyPattern = (pattern: string): void => {
+ try {
+ const keysToDelete = Object.keys(localStorage).filter(key => key.includes(pattern))
+ for (const key of keysToDelete) {
+ deleteFromLocalStorage(key)
+ }
+ } catch {
+ if (import.meta.env.DEV) {
+ console.debug(`[localStorage] Failed to delete keys matching '${pattern}'`)
+ }
+ }
+}
+
+/**
+ * Resets the state of a toggle button by removing its entry from localStorage.
+ * @param id - The identifier of the toggle button
+ * @param shared - Whether the toggle button is shared
+ */
+export const resetToggleButtonState = (id: string, shared = false): void => {
+ const key = shared
+ ? `${SHARED_TOGGLE_BUTTON_KEY_PREFIX}${id}`
+ : `${TOGGLE_BUTTON_KEY_PREFIX}${id}`
+ deleteFromLocalStorage(key)
+}
UI_SERVER_CONFIGURATION_INDEX_KEY,
UIClient,
uiClientKey,
-} from '@/composables/index.js'
+} from '@/core/index.js'
import { router } from '@/router'
import { SKIN_STORAGE_KEY, useSkin } from '@/shared/composables/useSkin.js'
import { DEFAULT_THEME, THEME_STORAGE_KEY, useTheme } from '@/shared/composables/useTheme.js'
import { createRouter, createWebHistory, type RouteLocationNormalized } from 'vue-router'
import { useToast } from 'vue-toast-notification'
-import { ROUTE_NAMES } from '@/composables/index.js'
+import { ROUTE_NAMES } from '@/core/index.js'
import { useSkin } from '@/shared/composables/useSkin.js'
import { DEFAULT_SKIN } from '@/skins/registry.js'
</template>
<script setup lang="ts">
-import { setToLocalStorage } from '@/composables/Utils.js'
+import { setToLocalStorage } from '@/core/index.js'
import { SKIN_STORAGE_KEY } from '@/shared/composables/useSkin.js'
import { DEFAULT_SKIN, skins } from '@/skins/registry.js'
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'
import { type DeepReadonly, readonly, ref, type Ref, watch } from 'vue'
import { useToast } from 'vue-toast-notification'
-import { useTemplates, useUIClient } from '@/composables/Utils.js'
+import { useTemplates, useUIClient } from '@/core/index.js'
export interface AddStationsFormState {
autoStart: boolean
import { computed, type MaybeRefOrGetter, readonly, toValue } from 'vue'
import { useToast } from 'vue-toast-notification'
-import { useUIClient } from '@/composables/Utils.js'
+import { useUIClient } from '@/core/index.js'
import { useAsyncAction } from '@/shared/composables/useAsyncAction.js'
interface ConnectorActionsDeps {
--- /dev/null
+import type { ResponsePayload } from 'ui-common'
+import type { Ref } from 'vue'
+
+import { ref as vueRef } from 'vue'
+import { useToast } from 'vue-toast-notification'
+
+export const useFetchData = (
+ clientFn: () => Promise<ResponsePayload>,
+ onSuccess: (response: ResponsePayload) => void,
+ errorMsg: string,
+ onError?: () => void
+): { fetch: () => void; fetching: Ref<boolean> } => {
+ 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)
+ })
+ }
+ }
+ return { fetch, fetching }
+}
shallowRef,
} from 'vue'
-import {
- useChargingStations,
- useConfiguration,
- useFetchData,
- useTemplates,
- useUIClient,
-} from '@/composables/index.js'
+import { useChargingStations, useConfiguration, useTemplates, useUIClient } from '@/core/index.js'
+
+import { useFetchData } from './useFetchData.js'
export interface LayoutData {
/** Fetches only the charging stations list. */
import { readonly, ref, type Ref } from 'vue'
import { useToast } from 'vue-toast-notification'
-import { useUIClient } from '@/composables/Utils.js'
+import { useUIClient } from '@/core/index.js'
export interface SetUrlFormState {
supervisionPassword: string
useChargingStations,
useConfiguration,
useUIClient,
-} from '@/composables/index.js'
+} from '@/core/index.js'
import { useAsyncAction } from '@/shared/composables/useAsyncAction.js'
import { type LayoutData } from '@/shared/composables/useLayoutData.js'
import { type SKIN_IDS } from 'ui-common'
import { readonly, ref, type Ref } from 'vue'
-import { getFromLocalStorage, setToLocalStorage } from '@/composables/Utils.js'
+import { getFromLocalStorage, setToLocalStorage } from '@/core/index.js'
import { validateTokenContract } from '@/shared/tokens/contract.js'
// Intentional: registry.ts is pure metadata (ids, labels, loaders) — no behavioral coupling.
import { DEFAULT_SKIN, type SkinDefinition, skins } from '@/skins/registry.js'
import { readonly, ref, type Ref } from 'vue'
import { useToast } from 'vue-toast-notification'
-import { useUIClient } from '@/composables/Utils.js'
+import { useUIClient } from '@/core/index.js'
export interface StartTxFormConfig {
connectorId: string
*/
import { readonly } from 'vue'
-import { useUIClient } from '@/composables/Utils.js'
+import { useUIClient } from '@/core/index.js'
import { useAsyncAction } from '@/shared/composables/useAsyncAction.js'
/**
import { THEME_IDS } from 'ui-common'
import { readonly, ref, type Ref } from 'vue'
-import { getFromLocalStorage, setToLocalStorage } from '@/composables/Utils.js'
+import { getFromLocalStorage, setToLocalStorage } from '@/core/index.js'
import { validateTokenContract } from '@/shared/tokens/contract.js'
export const AVAILABLE_THEMES = THEME_IDS
-import { EMPTY_VALUE_PLACEHOLDER } from '@/composables/Constants.js'
+import { EMPTY_VALUE_PLACEHOLDER } from '@/core/Constants.js'
export interface FormatSupervisionUrlOptions {
/** Insert zero-width-space after dots for word-break in table cells. */
TOGGLE_BUTTON_KEY_PREFIX,
UI_SERVER_CONFIGURATION_INDEX_KEY,
useChargingStations,
-} from '@/composables'
+} from '@/core'
import { useLayoutData } from '@/shared/composables/useLayoutData.js'
import { useSimulatorControl } from '@/shared/composables/useSimulatorControl.js'
import { useSkin } from '@/shared/composables/useSkin.js'
<script setup lang="ts">
import { useRouter } from 'vue-router'
-import { resetToggleButtonState, ROUTE_NAMES } from '@/composables'
+import { resetToggleButtonState, ROUTE_NAMES } from '@/core'
import { useAddStationsForm } from '@/shared/composables/useAddStationsForm.js'
import Button from '../buttons/ClassicButton.vue'
<script setup lang="ts">
import { useRouter } from 'vue-router'
-import { resetToggleButtonState, ROUTE_NAMES } from '@/composables'
+import { resetToggleButtonState, ROUTE_NAMES } from '@/core'
import { useSetUrlForm } from '@/shared/composables/useSetUrlForm.js'
import Button from '../buttons/ClassicButton.vue'
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
-import { resetToggleButtonState, ROUTE_NAMES } from '@/composables'
+import { resetToggleButtonState, ROUTE_NAMES } from '@/core'
import { useStartTxForm } from '@/shared/composables/useStartTxForm.js'
import Button from '../buttons/ClassicButton.vue'
setToLocalStorage,
SHARED_TOGGLE_BUTTON_KEY_PREFIX,
TOGGLE_BUTTON_KEY_PREFIX,
-} from '@/composables'
+} from '@/core'
import Button from './ClassicButton.vue'
import { computed } from 'vue'
import { useRouter } from 'vue-router'
-import { EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES } from '@/composables'
+import { EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES } from '@/core'
import { useConnectorActions } from '@/shared/composables/useConnectorActions.js'
import Button from '../buttons/ClassicButton.vue'
} from 'ui-common'
import { computed } from 'vue'
-import { deleteLocalStorageByKeyPattern, EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES } from '@/composables'
+import { deleteLocalStorageByKeyPattern, EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES } from '@/core'
import { useStationActions } from '@/shared/composables/useStationActions.js'
import { formatSupervisionUrl } from '@/shared/utils/formatSupervisionUrl.js'
import { getATGStatus, getConnectorEntries } from '@/shared/utils/stationStatus.js'
import { type OCPPVersion } from 'ui-common'
import { defineAsyncComponent, ref } from 'vue'
-import {
- getFromLocalStorage,
- UI_SERVER_CONFIGURATION_INDEX_KEY,
- useChargingStations,
-} from '@/composables'
+import { getFromLocalStorage, UI_SERVER_CONFIGURATION_INDEX_KEY, useChargingStations } from '@/core'
import SkinLoadError from '@/shared/components/SkinLoadError.vue'
import SkinLoading from '@/shared/components/SkinLoading.vue'
import { useLayoutData } from '@/shared/composables/useLayoutData.js'
} from 'ui-common'
import { computed, ref } from 'vue'
-import { deleteLocalStorageByKeyPattern, EMPTY_VALUE_PLACEHOLDER as EMPTY } from '@/composables'
+import { deleteLocalStorageByKeyPattern, EMPTY_VALUE_PLACEHOLDER as EMPTY } from '@/core'
import { useStationActions } from '@/shared/composables/useStationActions.js'
import { formatSupervisionUrl } from '@/shared/utils/formatSupervisionUrl.js'
import {
import { computed, ref } from 'vue'
import { useToast } from 'vue-toast-notification'
-import { useUIClient } from '@/composables'
+import { useUIClient } from '@/core'
import { type FailureInfo, getFailureInfo } from '../../utils/errors.js'
import ActionButton from '../ActionButton.vue'
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
-import { useChargingStations, useUIClient } from '@/composables'
+import { useChargingStations, useUIClient } from '@/core'
import { useSetUrlForm } from '@/shared/composables/useSetUrlForm.js'
import { stripStationId } from '@/shared/utils/stripStationId.js'
} from 'ui-common'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { UIClient } from '@/composables'
+import { UIClient } from '@/core'
import { toastMock } from '../setup'
import { createUIServerConfig, TEST_HASH_ID, TEST_ID_TAG } from './constants'
setToLocalStorage,
useChargingStations,
useConfiguration,
- useFetchData,
useTemplates,
-} from '@/composables'
+} from '@/core'
+import { useFetchData } from '@/shared/composables/useFetchData.js'
import { toastMock } from '../setup'
*/
import { describe, expect, it, vi } from 'vitest'
-import { ROUTE_NAMES } from '@/composables'
+import { ROUTE_NAMES } from '@/core'
import { router } from '@/router/index.js'
vi.mock('@/shared/composables/useSkin.js', async importOriginal => {
const mockAddChargingStations = vi.fn().mockResolvedValue({ status: 'success' })
const mockTemplates = ref(['template1.json', 'template2.json'])
-vi.mock('@/composables/Utils.js', () => ({
+vi.mock('@/core/index.js', () => ({
resetToggleButtonState: vi.fn(),
useTemplates: () => mockTemplates,
useUIClient: () => ({
let mockClient: MockUIClient
-vi.mock('@/composables/Utils.js', () => ({
+vi.mock('@/core/index.js', () => ({
useUIClient: () => mockClient,
}))
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { type Ref, ref } from 'vue'
-import { useChargingStations, useConfiguration, useTemplates, useUIClient } from '@/composables'
+import { useChargingStations, useConfiguration, useTemplates, useUIClient } from '@/core'
-vi.mock('@/composables', async importOriginal => {
+vi.mock('@/core', async importOriginal => {
const actual = await importOriginal()
return {
...(actual as Record<string, unknown>),
const mockSetSupervisionUrl = vi.fn().mockResolvedValue({ status: 'success' })
-vi.mock('@/composables/Utils.js', () => ({
+vi.mock('@/core/index.js', () => ({
useUIClient: () => ({
setSupervisionUrl: mockSetSupervisionUrl,
}),
useChargingStations,
useConfiguration,
useUIClient,
-} from '@/composables'
+} from '@/core'
import { toastMock } from '../../../setup.js'
import { createUIServerConfig } from '../../constants'
import { createMockUIClient, type MockUIClient, withSetup } from '../../helpers.js'
-vi.mock('@/composables', async importOriginal => {
+vi.mock('@/core', async importOriginal => {
const actual = await importOriginal()
return {
...(actual as Record<string, unknown>),
const mockAuthorize = vi.fn().mockResolvedValue({ status: 'success' })
const mockStartTransaction = vi.fn().mockResolvedValue({ status: 'success' })
-vi.mock('@/composables/Utils.js', () => ({
+vi.mock('@/core/index.js', () => ({
useUIClient: () => ({
authorize: mockAuthorize,
startTransaction: mockStartTransaction,
let mockUIClient: MockUIClient
-vi.mock('@/composables/Utils.js', () => ({
+vi.mock('@/core/index.js', () => ({
useUIClient: () => mockUIClient,
}))
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { ref, shallowRef } from 'vue'
-import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/composables'
+import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core'
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'
import { type ConnectorStatus, OCPP16ChargePointStatus, OCPPVersion } from 'ui-common'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { uiClientKey } from '@/composables'
+import { uiClientKey } from '@/core'
import CSConnector from '@/skins/classic/components/charging-stations/CSConnector.vue'
import { toastMock } from '../../../setup.js'
import { type ChargingStationData, OCPP16AvailabilityType, OCPPVersion } from 'ui-common'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { uiClientKey } from '@/composables'
+import { uiClientKey } from '@/core'
import CSData from '@/skins/classic/components/charging-stations/CSData.vue'
import { toastMock } from '../../../setup.js'
import { shallowMount } from '@vue/test-utils'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { uiClientKey } from '@/composables'
+import { uiClientKey } from '@/core'
import CSTable from '@/skins/classic/components/charging-stations/CSTable.vue'
import { createChargingStationData } from '../../constants.js'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { defineComponent, shallowRef } from 'vue'
-import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/composables'
+import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core'
import ToggleButton from '@/skins/classic/components/buttons/ToggleButton.vue'
import CSTable from '@/skins/classic/components/charging-stations/CSTable.vue'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'
-import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/composables'
+import { chargingStationsKey, configurationKey, templatesKey, uiClientKey } from '@/core'
import ClassicLayout from '@/skins/classic/ClassicLayout.vue'
import { createUIServerConfig } from '../../constants'
} from 'ui-common'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { uiClientKey } from '@/composables'
+import { uiClientKey } from '@/core'
import ConnectorRow from '@/skins/modern/components/ConnectorRow.vue'
import { toastMock } from '../../../setup.js'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { defineComponent, ref } from 'vue'
-import { chargingStationsKey, templatesKey, uiClientKey } from '@/composables'
+import { chargingStationsKey, templatesKey, uiClientKey } from '@/core'
// Mock Modal to render slots inline (no Teleport), so `wrapper.find()` works.
vi.mock('@/skins/modern/components/ModernModal.vue', () => ({
UI_SERVER_CONFIGURATION_INDEX_KEY,
uiClientKey,
useUIClient,
-} from '@/composables'
+} from '@/core'
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('@/composables', async importOriginal => {
+vi.mock('@/core', async importOriginal => {
const actual = await importOriginal()
return { ...(actual as Record<string, unknown>), useUIClient: vi.fn() }
})
import { type ChargingStationData, OCPP16AvailabilityType } from 'ui-common'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { uiClientKey } from '@/composables'
+import { uiClientKey } from '@/core'
import StationCard from '@/skins/modern/components/StationCard.vue'
import { toastMock } from '../../../setup.js'