]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor: enforce utility usage and centralize constants across all components
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 3 Apr 2026 20:56:28 +0000 (22:56 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 3 Apr 2026 20:56:28 +0000 (22:56 +0200)
- Replace .length/.size checks with isEmpty/isNotEmptyArray in 7 src/ files
- Replace Number.parseInt/parseFloat with convertToInt in OCPPServiceUtils
  (intentional fail-fast: malformed templates now throw instead of silent NaN)
- Keep Number.parseFloat in getLimitFromSampledValueTemplateCustomValue
  (NaN fallback contract requires it)
- Centralize route names (ROUTE_NAMES), placeholder (EMPTY_VALUE_PLACEHOLDER),
  and localStorage key in Vue UI (11 files)
- Extract 13 magic values to constants in Python ocpp-server
- Rename constants: WORKER_SET_VERSION, DEFAULT_RATE_WINDOW_MS, MS_PER_HOUR,
  DEFAULT_*_SECONDS in Python, DEFAULT_*_BYTES in UIServerSecurity

30 files changed:
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/ChargingStation.ts
src/charging-station/Helpers.ts
src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts
src/charging-station/ocpp/OCPPServiceUtils.ts
src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts
src/charging-station/ui-server/AbstractUIServer.ts
src/charging-station/ui-server/UIHttpServer.ts
src/charging-station/ui-server/UIMCPServer.ts
src/charging-station/ui-server/UIServerSecurity.ts
src/charging-station/ui-server/UIWebSocketServer.ts
src/worker/WorkerConstants.ts
src/worker/WorkerSet.ts
tests/charging-station/ChargingStationTestConstants.ts
tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-ReconnectDelay.test.ts
tests/charging-station/ui-server/UIHttpServer.test.ts
tests/charging-station/ui-server/UIMCPServer.test.ts
tests/ocpp-server/server.py
tests/ocpp-server/test_server.py
ui/web/src/App.vue
ui/web/src/components/actions/AddChargingStations.vue
ui/web/src/components/actions/SetSupervisionUrl.vue
ui/web/src/components/actions/StartTransaction.vue
ui/web/src/components/charging-stations/CSConnector.vue
ui/web/src/components/charging-stations/CSData.vue
ui/web/src/composables/Constants.ts
ui/web/src/composables/index.ts
ui/web/src/main.ts
ui/web/src/router/index.ts
ui/web/src/views/ChargingStationsView.vue

index 6a73c97e56b272f303d588ccdc967673254f57a4..ca65b7d6186dd67d7c27afe38fd4b2c4dc6815a2 100644 (file)
@@ -20,6 +20,7 @@ import {
   Constants,
   convertToDate,
   formatDurationMilliSeconds,
+  isEmpty,
   isValidDate,
   logger,
   logPrefix,
@@ -385,7 +386,7 @@ export class AutomaticTransactionGenerator {
 
   private startConnectors (stopAbsoluteDuration?: boolean): void {
     if (
-      this.connectorsStatus.size > 0 &&
+      !isEmpty(this.connectorsStatus) &&
       this.connectorsStatus.size !== this.chargingStation.getNumberOfConnectors()
     ) {
       this.connectorsStatus.clear()
index 3f64f267375c19f30d00db6ee71ea4b4416cbde9..716b8e42f96958d7cdefcd756a99101b3088ca9c 100644 (file)
@@ -177,7 +177,7 @@ export class ChargingStation extends EventEmitter {
   public wsConnection: null | WebSocket
 
   public get hasEvses (): boolean {
-    return isEmpty(this.connectors) && this.evses.size > 0
+    return isEmpty(this.connectors) && !isEmpty(this.evses)
   }
 
   public get wsConnectionUrl (): URL {
@@ -1233,7 +1233,7 @@ export class ChargingStation extends EventEmitter {
   }
 
   private flushMessageBuffer (): void {
-    if (!this.flushingMessageBuffer && this.messageQueue.length > 0) {
+    if (!this.flushingMessageBuffer && isNotEmptyArray<string>(this.messageQueue)) {
       this.flushingMessageBuffer = true
       this.sendMessageBuffer(() => {
         this.flushingMessageBuffer = false
@@ -1862,7 +1862,7 @@ export class ChargingStation extends EventEmitter {
   private initializeConnectorsOrEvsesFromFile (configuration: ChargingStationConfiguration): void {
     if (configuration.connectorsStatus != null && configuration.evsesStatus == null) {
       const isTupleFormat =
-        configuration.connectorsStatus.length > 0 &&
+        isNotEmptyArray(configuration.connectorsStatus) &&
         Array.isArray(configuration.connectorsStatus[0])
       const entries: [number, ConnectorStatus][] = isTupleFormat
         ? (configuration.connectorsStatus as [number, ConnectorStatus][])
@@ -1875,7 +1875,7 @@ export class ChargingStation extends EventEmitter {
       }
     } else if (configuration.evsesStatus != null && configuration.connectorsStatus == null) {
       const isTupleFormat =
-        configuration.evsesStatus.length > 0 && Array.isArray(configuration.evsesStatus[0])
+        isNotEmptyArray(configuration.evsesStatus) && Array.isArray(configuration.evsesStatus[0])
       const evseEntries: [number, EvseStatusConfiguration][] = isTupleFormat
         ? (configuration.evsesStatus as [number, EvseStatusConfiguration][])
         : (configuration.evsesStatus as EvseStatusConfiguration[]).map((status, index) => [
@@ -1887,7 +1887,7 @@ export class ChargingStation extends EventEmitter {
         delete evseStatus.connectorsStatus
         const connIsTupleFormat =
           evseStatusConfiguration.connectorsStatus != null &&
-          evseStatusConfiguration.connectorsStatus.length > 0 &&
+          isNotEmptyArray(evseStatusConfiguration.connectorsStatus) &&
           Array.isArray(evseStatusConfiguration.connectorsStatus[0])
         const connEntries: [number, ConnectorStatus][] = connIsTupleFormat
           ? (evseStatusConfiguration.connectorsStatus as [number, ConnectorStatus][])
@@ -2436,12 +2436,12 @@ export class ChargingStation extends EventEmitter {
         if (this.stationInfo?.automaticTransactionGeneratorPersistentConfiguration !== true) {
           delete configurationData.automaticTransactionGenerator
         }
-        if (this.connectors.size > 0) {
+        if (!isEmpty(this.connectors)) {
           configurationData.connectorsStatus = buildConnectorsStatus(this)
         } else {
           delete configurationData.connectorsStatus
         }
-        if (this.evses.size > 0) {
+        if (!isEmpty(this.evses)) {
           configurationData.evsesStatus = buildEvsesStatus(this)
         } else {
           delete configurationData.evsesStatus
@@ -2453,10 +2453,10 @@ export class ChargingStation extends EventEmitter {
             automaticTransactionGenerator: configurationData.automaticTransactionGenerator,
             configurationKey: configurationData.configurationKey,
             stationInfo: configurationData.stationInfo,
-            ...(this.connectors.size > 0 && {
+            ...(!isEmpty(this.connectors) && {
               connectorsStatus: configurationData.connectorsStatus,
             }),
-            ...(this.evses.size > 0 && {
+            ...(!isEmpty(this.evses) && {
               evsesStatus: configurationData.evsesStatus,
             }),
           } satisfies ChargingStationConfiguration),
@@ -2524,7 +2524,7 @@ export class ChargingStation extends EventEmitter {
     onCompleteCallback: () => void,
     messageIdx?: number
   ): void => {
-    if (this.messageQueue.length > 0) {
+    if (isNotEmptyArray<string>(this.messageQueue)) {
       const message = this.messageQueue[0]
       let beginId: string | undefined
       let commandName: RequestCommand | undefined
index 780a72d52d0dc31ab154dd6f123b927a8f646902..a51b9c70dda03990b4cd987829cb17f841e46680 100644 (file)
@@ -272,7 +272,7 @@ export const getMaxNumberOfEvses = (evses: Record<string, EvseTemplate> | undefi
   if (evses == null) {
     return -1
   }
-  return Object.keys(evses).length
+  return isEmpty(evses) ? 0 : Object.keys(evses).length
 }
 
 const getMaxNumberOfConnectors = (
@@ -281,7 +281,7 @@ const getMaxNumberOfConnectors = (
   if (connectors == null) {
     return -1
   }
-  return Object.keys(connectors).length
+  return isEmpty(connectors) ? 0 : Object.keys(connectors).length
 }
 
 export const getBootConnectorStatus = (
index 7dc41c2bf1a27d04ba3898b90d1efb74f00695a7..3598d17640b5b897d574fc496890d6322f0ede89 100644 (file)
@@ -11,6 +11,7 @@ import {
   OCPP20ComponentName,
   type OCPP20ConnectorStatusEnumType,
   type OCPP20EVSEType,
+  type OCPP20GetVariableResultType,
   OCPP20IdTokenEnumType,
   type OCPP20IdTokenInfoType,
   type OCPP20IdTokenType,
@@ -531,7 +532,10 @@ export class OCPP20ServiceUtils {
         variable: { name: variableName },
       },
     ])
-    if (results.length > 0 && results[0].attributeValue != null) {
+    if (
+      isNotEmptyArray<OCPP20GetVariableResultType>(results) &&
+      results[0].attributeValue != null
+    ) {
       return results[0].attributeValue
     }
     return undefined
index b4826ec8cbfbfbfa0d03cba2c8e9609697d79750..b022c19acedea8d657d4807c8d50dc8e60ac00ef 100644 (file)
@@ -67,7 +67,7 @@ const moduleName = 'OCPPServiceUtils'
 
 const SOC_MAXIMUM_VALUE = 100
 const UNIT_DIVIDER_KILO = 1000
-const MILLISECONDS_PER_HOUR = 3_600_000
+const MS_PER_HOUR = 3_600_000
 
 export type Ajv = _Ajv.default
 // eslint-disable-next-line @typescript-eslint/no-redeclare
@@ -235,7 +235,7 @@ const buildSocMeasurandValue = (
   const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0
   const socSampledValueTemplateValue = isNotEmptyString(socSampledValueTemplate.value)
     ? getRandomFloatFluctuatedRounded(
-      Number.parseInt(socSampledValueTemplate.value),
+      convertToInt(socSampledValueTemplate.value),
       socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
     )
     : randomInt(socMinimumValue, socMaximumValue + 1)
@@ -292,7 +292,7 @@ const buildVoltageMeasurandValue = (
   }
 
   const voltageSampledValueTemplateValue = isNotEmptyString(voltageSampledValueTemplate.value)
-    ? Number.parseInt(voltageSampledValueTemplate.value)
+    ? convertToInt(voltageSampledValueTemplate.value)
     : chargingStation.getVoltageOut()
   const fluctuationPercent =
     voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
@@ -361,7 +361,7 @@ const addPhaseVoltageToMeterValue = <TSampledValue extends SampledValue>(
   let phaseMeasurandValue: number | undefined
   if (phaseSampledValueTemplate != null) {
     const templateValue = isNotEmptyString(phaseSampledValueTemplate.value)
-      ? Number.parseInt(phaseSampledValueTemplate.value)
+      ? convertToInt(phaseSampledValueTemplate.value)
       : nominalVoltage
     phaseMeasurandValue = getRandomFloatFluctuatedRounded(
       templateValue,
@@ -401,7 +401,7 @@ const buildEnergyMeasurandValue = (
   const connectorMaximumAvailablePower =
     chargingStation.getConnectorMaximumAvailablePower(connectorId)
   const connectorMaximumEnergyRounded = roundTo(
-    (connectorMaximumAvailablePower * interval) / MILLISECONDS_PER_HOUR,
+    (connectorMaximumAvailablePower * interval) / MS_PER_HOUR,
     2
   )
   const connectorMinimumEnergyRounded = roundTo(energyTemplate.minimumValue ?? 0, 2)
@@ -1155,7 +1155,7 @@ export const buildMeterValue = (
     const connectorMaximumAvailablePower =
       chargingStation.getConnectorMaximumAvailablePower(connectorId)
     const connectorMaximumEnergyRounded = roundTo(
-      (connectorMaximumAvailablePower * interval) / MILLISECONDS_PER_HOUR,
+      (connectorMaximumAvailablePower * interval) / MS_PER_HOUR,
       2
     )
     const connectorMinimumEnergyRounded = roundTo(energyMeasurand.template.minimumValue ?? 0, 2)
index 039be166c127d66fbb966239b58a17d05ec024c8..ca4a5c5b3a803efb9515ccbd2e3f8f79d0202fec 100644 (file)
@@ -3,7 +3,7 @@ import { secondsToMilliseconds } from 'date-fns'
 import type { AuthCache, CacheStats } from '../interfaces/OCPPAuthService.js'
 import type { AuthorizationResult } from '../types/AuthTypes.js'
 
-import { Constants, logger, roundTo, truncateId } from '../../../../utils/index.js'
+import { Constants, isEmpty, logger, roundTo, truncateId } from '../../../../utils/index.js'
 import { AuthorizationStatus } from '../types/AuthTypes.js'
 
 const moduleName = 'InMemoryAuthCache'
@@ -429,7 +429,7 @@ export class InMemoryAuthCache implements AuthCache {
    * Evict least recently used entry
    */
   private evictLRU (): void {
-    if (this.lruOrder.size === 0) {
+    if (isEmpty(this.lruOrder)) {
       return
     }
 
index 04d4d5abc477c38596af02ec60d724f216061180..752da6537fe752ef68d216bfe5a8f84d56d04211 100644 (file)
@@ -26,7 +26,7 @@ import { UIServiceFactory } from './ui-services/UIServiceFactory.js'
 import {
   createRateLimiter,
   DEFAULT_RATE_LIMIT,
-  DEFAULT_RATE_WINDOW,
+  DEFAULT_RATE_WINDOW_MS,
   isValidCredential,
 } from './UIServerSecurity.js'
 import { getUsernameAndPasswordFromAuthorizationToken } from './UIServerUtils.js'
@@ -70,7 +70,7 @@ export abstract class AbstractUIServer {
         )
     }
     this.responseHandlers = new Map<UUIDv4, ServerResponse | WebSocket>()
-    this.rateLimiter = createRateLimiter(DEFAULT_RATE_LIMIT, DEFAULT_RATE_WINDOW)
+    this.rateLimiter = createRateLimiter(DEFAULT_RATE_LIMIT, DEFAULT_RATE_WINDOW_MS)
     this.uiServices = new Map<ProtocolVersion, AbstractUIService>()
   }
 
index 8dce2ca3755fe6148278aa74c9b0d91fe8d1b1d2..3e79fdde3907ad01f15b8c52f11c0aa592a0a75d 100644 (file)
@@ -23,8 +23,8 @@ import { generateUUID, getErrorMessage, JSONStringify, logger } from '../../util
 import { AbstractUIServer } from './AbstractUIServer.js'
 import {
   createBodySizeLimiter,
-  DEFAULT_COMPRESSION_THRESHOLD,
-  DEFAULT_MAX_PAYLOAD_SIZE,
+  DEFAULT_COMPRESSION_THRESHOLD_BYTES,
+  DEFAULT_MAX_PAYLOAD_SIZE_BYTES,
 } from './UIServerSecurity.js'
 import { HttpMethod, isProtocolAndVersionSupported } from './UIServerUtils.js'
 
@@ -62,7 +62,7 @@ export class UIHttpServer extends AbstractUIServer {
         const body = JSONStringify(payload, undefined, MapStringifyFormat.object)
         const shouldCompress =
           this.acceptsGzip.get(uuid) === true &&
-          Buffer.byteLength(body) >= DEFAULT_COMPRESSION_THRESHOLD
+          Buffer.byteLength(body) >= DEFAULT_COMPRESSION_THRESHOLD_BYTES
 
         if (shouldCompress) {
           res.writeHead(this.responseStatusToStatusCode(payload.status), {
@@ -179,7 +179,7 @@ export class UIHttpServer extends AbstractUIServer {
         }
 
         const bodyBuffer: Uint8Array[] = []
-        const checkBodySize = createBodySizeLimiter(DEFAULT_MAX_PAYLOAD_SIZE)
+        const checkBodySize = createBodySizeLimiter(DEFAULT_MAX_PAYLOAD_SIZE_BYTES)
         req
           .on('data', (chunk: Uint8Array) => {
             if (!checkBodySize(chunk.length)) {
index 1045e49ed343226e0631d472d48899b8348097f9..cbeaea3e7f2901f40390932c1e71019bb0541c4e 100644 (file)
@@ -22,7 +22,13 @@ import {
   type UIServerConfiguration,
   type UUIDv4,
 } from '../../types/index.js'
-import { generateUUID, getErrorMessage, isNotEmptyArray, logger } from '../../utils/index.js'
+import {
+  generateUUID,
+  getErrorMessage,
+  isEmpty,
+  isNotEmptyArray,
+  logger,
+} from '../../utils/index.js'
 import { AbstractUIServer } from './AbstractUIServer.js'
 import {
   mcpToolSchemas,
@@ -31,7 +37,7 @@ import {
   registerMCPResources,
   registerMCPSchemaResources,
 } from './mcp/index.js'
-import { DEFAULT_MAX_PAYLOAD_SIZE } from './UIServerSecurity.js'
+import { DEFAULT_MAX_PAYLOAD_SIZE_BYTES } from './UIServerSecurity.js'
 import { HttpMethod } from './UIServerUtils.js'
 
 const moduleName = 'UIMCPServer'
@@ -284,7 +290,7 @@ export class UIMCPServer extends AbstractUIServer {
   }
 
   private injectOcppJsonSchemas (mcpServer: McpServer): void {
-    if (this.ocppSchemaCache.size === 0) {
+    if (isEmpty(this.ocppSchemaCache)) {
       return
     }
     // Access MCP SDK internal handler map — pinned to @modelcontextprotocol/sdk@~1.29.x
@@ -439,7 +445,7 @@ export class UIMCPServer extends AbstractUIServer {
         cache.set(procedureName, entry)
       }
     }
-    if (cache.size > 0) {
+    if (!isEmpty(cache)) {
       logger.info(
         `${this.logPrefix(moduleName, 'loadOcppSchemas')} OCPP JSON schema injection enabled for ${cache.size.toString()} tool(s)`
       )
@@ -452,7 +458,7 @@ export class UIMCPServer extends AbstractUIServer {
     let received = 0
     for await (const chunk of req) {
       received += (chunk as Buffer).length
-      if (received > DEFAULT_MAX_PAYLOAD_SIZE) {
+      if (received > DEFAULT_MAX_PAYLOAD_SIZE_BYTES) {
         throw new BaseError('Payload too large')
       }
       chunks.push(chunk as Buffer)
index fa5b9a83ba8ec60bb1d272b56354a7f49b4961cd..27c545ea4c28be4443315fba8bf4f50bb038eaaa 100644 (file)
@@ -5,12 +5,12 @@ interface RateLimitEntry {
   resetTime: number
 }
 
-export const DEFAULT_MAX_PAYLOAD_SIZE = 1048576
+export const DEFAULT_MAX_PAYLOAD_SIZE_BYTES = 1048576
 export const DEFAULT_RATE_LIMIT = 100
-export const DEFAULT_RATE_WINDOW = 60000
+export const DEFAULT_RATE_WINDOW_MS = 60000
 export const DEFAULT_MAX_STATIONS = 100
 export const DEFAULT_MAX_TRACKED_IPS = 10000
-export const DEFAULT_COMPRESSION_THRESHOLD = 1024
+export const DEFAULT_COMPRESSION_THRESHOLD_BYTES = 1024
 
 export const isValidCredential = (provided: string, expected: string): boolean => {
   try {
index 51b39b70de44e9b96c39a8c594bd4895f91cd104..4684560aeb5682ee4f1bae4400eff22aaa20fb4c 100644 (file)
@@ -22,7 +22,10 @@ import {
   validateUUID,
 } from '../../utils/index.js'
 import { AbstractUIServer } from './AbstractUIServer.js'
-import { DEFAULT_COMPRESSION_THRESHOLD, DEFAULT_MAX_PAYLOAD_SIZE } from './UIServerSecurity.js'
+import {
+  DEFAULT_COMPRESSION_THRESHOLD_BYTES,
+  DEFAULT_MAX_PAYLOAD_SIZE_BYTES,
+} from './UIServerSecurity.js'
 import {
   getProtocolAndVersion,
   handleProtocols,
@@ -43,14 +46,14 @@ export class UIWebSocketServer extends AbstractUIServer {
     super(uiServerConfiguration, bootstrap)
     this.webSocketServer = new WebSocketServer({
       handleProtocols,
-      maxPayload: DEFAULT_MAX_PAYLOAD_SIZE,
+      maxPayload: DEFAULT_MAX_PAYLOAD_SIZE_BYTES,
       noServer: true,
       perMessageDeflate: {
         clientNoContextTakeover: true,
         concurrencyLimit: 10,
         serverMaxWindowBits: 12,
         serverNoContextTakeover: true,
-        threshold: DEFAULT_COMPRESSION_THRESHOLD,
+        threshold: DEFAULT_COMPRESSION_THRESHOLD_BYTES,
         zlibDeflateOptions: {
           chunkSize: 16 * 1024,
           level: 6,
index b7460257ed7f3ac0f8c7ccf3b860aae5d1d46c63..2a25f1c8e9cb039afa0ddd4f3cd70658cf29ed64 100644 (file)
@@ -8,7 +8,7 @@ export const EMPTY_FUNCTION = Object.freeze(() => {
   /* This is intentional */
 })
 
-export const workerSetVersion = '1.0.1'
+export const WORKER_SET_VERSION = '1.0.1'
 
 export const DEFAULT_ELEMENT_ADD_DELAY_MS = 0
 export const DEFAULT_WORKER_START_DELAY_MS = 500
index b8e4ec24495fefc848ee8cf364543b390a9ab54b..7fd618b46d70d3080fb51c3c8302dfa550dd046d 100644 (file)
@@ -5,7 +5,11 @@ import { EventEmitterAsyncResource } from 'node:events'
 import { SHARE_ENV, Worker } from 'node:worker_threads'
 
 import { WorkerAbstract } from './WorkerAbstract.js'
-import { DEFAULT_ELEMENTS_PER_WORKER, EMPTY_FUNCTION, workerSetVersion } from './WorkerConstants.js'
+import {
+  DEFAULT_ELEMENTS_PER_WORKER,
+  EMPTY_FUNCTION,
+  WORKER_SET_VERSION,
+} from './WorkerConstants.js'
 import {
   type SetInfo,
   type UUIDv4,
@@ -37,7 +41,7 @@ export class WorkerSet<D extends WorkerData, R extends WorkerData> extends Worke
       size: this.size,
       started: this.started,
       type: 'set',
-      version: workerSetVersion,
+      version: WORKER_SET_VERSION,
       worker: 'thread',
     }
   }
index 06baa4d72eabc51d6670296f340fadf849d8a4a4..4560d1d25436bb6ebea4af4a2139a06c3bf55b37 100644 (file)
@@ -16,7 +16,7 @@ export const TEST_CHARGING_STATION_BASE_NAME = 'CS-TEST'
 export const TEST_CHARGING_STATION_HASH_ID = 'cs-test-hash-001'
 
 /**
- * Timer Intervals (seconds)
+ * Timer Intervals
  * Test values for timing-related configuration and expectations
  */
 export const TEST_HEARTBEAT_INTERVAL_SECONDS = 60
index 0f7958405e27d11684873f4bd35cbdfbd132bd9c..890691e777a9a594d5f5e619edebef5eae20455c 100644 (file)
@@ -22,8 +22,8 @@ import { TEST_CHARGING_STATION_BASE_NAME } from '../../ChargingStationTestConsta
 import { createMockChargingStation } from '../../ChargingStationTestUtils.js'
 import { upsertConfigurationKey } from './OCPP20TestUtils.js'
 
-const DEFAULT_WAIT_MINIMUM_S = 30
-const DEFAULT_RANDOM_RANGE_S = 10
+const DEFAULT_WAIT_MINIMUM_SECONDS = 30
+const DEFAULT_RANDOM_RANGE_SECONDS = 10
 const DEFAULT_REPEAT_TIMES = 5
 
 const MS_PER_SECOND = 1000
@@ -116,8 +116,8 @@ await describe('OCPP20ServiceUtils.computeReconnectDelay', async () => {
     const delay = OCPP20ServiceUtils.computeReconnectDelay(station, retryCount)
 
     // Assert — retryCount=1 → effectiveRetry=0 → baseDelay = 30s * 2^0 = 30000ms
-    const expectedBaseDelayMs = DEFAULT_WAIT_MINIMUM_S * MS_PER_SECOND
-    const maxJitterMs = DEFAULT_RANDOM_RANGE_S * MS_PER_SECOND
+    const expectedBaseDelayMs = DEFAULT_WAIT_MINIMUM_SECONDS * MS_PER_SECOND
+    const maxJitterMs = DEFAULT_RANDOM_RANGE_SECONDS * MS_PER_SECOND
     assert.ok(delay >= expectedBaseDelayMs, 'delay should be >= default base')
     assert.ok(delay < expectedBaseDelayMs + maxJitterMs, 'delay should be < default base + jitter')
   })
@@ -132,8 +132,9 @@ await describe('OCPP20ServiceUtils.computeReconnectDelay', async () => {
 
     // Assert — both capped: effectiveRetry = min(retryCount-1, repeatTimes) = 5
     // baseDelay = 30s * 2^5 = 960000ms
-    const cappedBaseDelayMs = DEFAULT_WAIT_MINIMUM_S * MS_PER_SECOND * 2 ** DEFAULT_REPEAT_TIMES
-    const maxJitterMs = DEFAULT_RANDOM_RANGE_S * MS_PER_SECOND
+    const cappedBaseDelayMs =
+      DEFAULT_WAIT_MINIMUM_SECONDS * MS_PER_SECOND * 2 ** DEFAULT_REPEAT_TIMES
+    const maxJitterMs = DEFAULT_RANDOM_RANGE_SECONDS * MS_PER_SECOND
     assert.ok(delayBeyondCap >= cappedBaseDelayMs, 'beyond-cap delay should be >= capped base')
     assert.ok(
       delayBeyondCap < cappedBaseDelayMs + maxJitterMs,
index 906681c74d091dc96b25f6e00067e8edb2a81291..7ca34ca3e14432e4e683c156a8e3455a2b01ad7f 100644 (file)
@@ -10,7 +10,7 @@ import { gunzipSync } from 'node:zlib'
 import type { UIServerConfiguration, UUIDv4 } from '../../../src/types/index.js'
 
 import { UIHttpServer } from '../../../src/charging-station/ui-server/UIHttpServer.js'
-import { DEFAULT_COMPRESSION_THRESHOLD } from '../../../src/charging-station/ui-server/UIServerSecurity.js'
+import { DEFAULT_COMPRESSION_THRESHOLD_BYTES } from '../../../src/charging-station/ui-server/UIServerSecurity.js'
 import { ApplicationProtocol, ResponseStatus } from '../../../src/types/index.js'
 import { standardCleanup } from '../../helpers/TestLifecycleHelpers.js'
 import { GZIP_STREAM_FLUSH_DELAY_MS, TEST_UUID } from './UIServerTestConstants.js'
@@ -49,7 +49,7 @@ const createHttpServerConfig = () =>
   createMockUIServerConfiguration({ type: ApplicationProtocol.HTTP })
 
 const createLargePayload = (status: ResponseStatus = ResponseStatus.SUCCESS) => ({
-  data: 'x'.repeat(DEFAULT_COMPRESSION_THRESHOLD + 100),
+  data: 'x'.repeat(DEFAULT_COMPRESSION_THRESHOLD_BYTES + 100),
   status,
 })
 
index 3c5df4bce3a2c7dac1e377207556f3bf4b516718..ce84b8b5affa568b30179272f19b1f867643ad8f 100644 (file)
@@ -25,7 +25,7 @@ import {
 } from '../../../src/charging-station/ui-server/mcp/index.js'
 import { AbstractUIService } from '../../../src/charging-station/ui-server/ui-services/AbstractUIService.js'
 import { UIMCPServer } from '../../../src/charging-station/ui-server/UIMCPServer.js'
-import { DEFAULT_MAX_PAYLOAD_SIZE } from '../../../src/charging-station/ui-server/UIServerSecurity.js'
+import { DEFAULT_MAX_PAYLOAD_SIZE_BYTES } from '../../../src/charging-station/ui-server/UIServerSecurity.js'
 import { BaseError } from '../../../src/exception/index.js'
 import {
   ApplicationProtocol,
@@ -671,7 +671,7 @@ await describe('UIMCPServer', async () => {
     })
 
     await it('should reject with BaseError when payload too large', async () => {
-      const oversizedChunk = Buffer.alloc(DEFAULT_MAX_PAYLOAD_SIZE + 1)
+      const oversizedChunk = Buffer.alloc(DEFAULT_MAX_PAYLOAD_SIZE_BYTES + 1)
       const mockReq = Readable.from([oversizedChunk])
 
       await assert.rejects(
index 0ebab66172df90088d6bdaef01e7843d838d4299..e8f88bc92a631ec8f4d07c43ca6bc47f43612cd8 100644 (file)
@@ -58,11 +58,23 @@ logger = logging.getLogger(__name__)
 # Server defaults
 DEFAULT_HOST = "127.0.0.1"
 DEFAULT_PORT = 9000
-DEFAULT_HEARTBEAT_INTERVAL = 60
+DEFAULT_HEARTBEAT_INTERVAL_SECONDS = 60
+DEFAULT_MESSAGE_TIMEOUT_SECONDS = 30
 DEFAULT_TOTAL_COST = 10.0
+DEFAULT_SECURITY_PROFILE = 0
+DEFAULT_CONFIG_SLOT = 1
+DEFAULT_EVSE_ID = 1
+DEFAULT_CONNECTOR_ID = 1
+DEFAULT_OCPP_CSMS_URL = "ws://127.0.0.1:9000"
+DEFAULT_TEST_TOKEN = "test_token"  # noqa: S105
+DEFAULT_TOKEN_TYPE = "ISO14443"  # noqa: S105
+DEFAULT_VENDOR_ID = "TestVendor"
+DEFAULT_FIRMWARE_URL = "https://example.com/firmware/v2.0.bin"
+DEFAULT_LOG_URL = "https://example.com/logs"
+DEFAULT_CUSTOMER_ID = "test_customer_001"
 FALLBACK_TRANSACTION_ID = "test_transaction_123"
 MAX_REQUEST_ID = 2**31 - 1
-SHUTDOWN_TIMEOUT = 30.0
+SHUTDOWN_TIMEOUT_SECONDS = 30.0
 SUBPROTOCOLS: list[websockets.Subprotocol] = [
     websockets.Subprotocol("ocpp2.0"),
     websockets.Subprotocol("ocpp2.0.1"),
@@ -236,7 +248,7 @@ class ChargePoint(ocpp.v201.ChargePoint):
         self._boot_index[0] = idx + 1
         return ocpp.v201.call_result.BootNotification(
             current_time=datetime.now(timezone.utc).isoformat(),
-            interval=DEFAULT_HEARTBEAT_INTERVAL,
+            interval=DEFAULT_HEARTBEAT_INTERVAL_SECONDS,
             status=status,
         )
 
@@ -442,8 +454,8 @@ class ChargePoint(ocpp.v201.ChargePoint):
 
     async def _send_request_start_transaction(self):
         request = ocpp.v201.call.RequestStartTransaction(
-            id_token={"id_token": "test_token", "type": "ISO14443"},
-            evse_id=1,
+            id_token={"id_token": DEFAULT_TEST_TOKEN, "type": DEFAULT_TOKEN_TYPE},
+            evse_id=DEFAULT_EVSE_ID,
             remote_start_id=_random_request_id(),
         )
         await self.call(request, suppress=False)
@@ -468,7 +480,9 @@ class ChargePoint(ocpp.v201.ChargePoint):
         await self._call_and_log(request, Action.reset, ResetStatusEnumType.accepted)
 
     async def _send_unlock_connector(self):
-        request = ocpp.v201.call.UnlockConnector(evse_id=1, connector_id=1)
+        request = ocpp.v201.call.UnlockConnector(
+            evse_id=DEFAULT_EVSE_ID, connector_id=DEFAULT_CONNECTOR_ID
+        )
         await self._call_and_log(
             request, Action.unlock_connector, UnlockStatusEnumType.unlocked
         )
@@ -493,7 +507,7 @@ class ChargePoint(ocpp.v201.ChargePoint):
 
     async def _send_data_transfer(self):
         request = ocpp.v201.call.DataTransfer(
-            vendor_id="TestVendor", message_id="TestMessage", data="test_data"
+            vendor_id=DEFAULT_VENDOR_ID, message_id="TestMessage", data="test_data"
         )
         await self._call_and_log(
             request, Action.data_transfer, DataTransferStatusEnumType.accepted
@@ -519,7 +533,7 @@ class ChargePoint(ocpp.v201.ChargePoint):
             request_id=_random_request_id(),
             report=True,
             clear=False,
-            customer_identifier="test_customer_001",
+            customer_identifier=DEFAULT_CUSTOMER_ID,
         )
         await self._call_and_log(
             request,
@@ -554,7 +568,7 @@ class ChargePoint(ocpp.v201.ChargePoint):
 
     async def _send_get_log(self):
         request = ocpp.v201.call.GetLog(
-            log={"remote_location": "https://example.com/logs"},
+            log={"remote_location": DEFAULT_LOG_URL},
             log_type=LogEnumType.diagnostics_log,
             request_id=_random_request_id(),
         )
@@ -589,13 +603,13 @@ class ChargePoint(ocpp.v201.ChargePoint):
 
     async def _send_set_network_profile(self):
         request = ocpp.v201.call.SetNetworkProfile(
-            configuration_slot=1,
+            configuration_slot=DEFAULT_CONFIG_SLOT,
             connection_data={
                 "ocpp_version": "OCPP20",
                 "ocpp_transport": "JSON",
-                "ocpp_csms_url": "ws://127.0.0.1:9000",
-                "message_timeout": 30,
-                "security_profile": 0,
+                "ocpp_csms_url": DEFAULT_OCPP_CSMS_URL,
+                "message_timeout": DEFAULT_MESSAGE_TIMEOUT_SECONDS,
+                "security_profile": DEFAULT_SECURITY_PROFILE,
                 "ocpp_interface": "Wired0",
             },
         )
@@ -609,7 +623,7 @@ class ChargePoint(ocpp.v201.ChargePoint):
         request = ocpp.v201.call.UpdateFirmware(
             request_id=_random_request_id(),
             firmware={
-                "location": "https://example.com/firmware/v2.0.bin",
+                "location": DEFAULT_FIRMWARE_URL,
                 "retrieve_date_time": datetime.now(timezone.utc).isoformat(),
             },
         )
@@ -1099,13 +1113,13 @@ async def main():
         await shutdown_event.wait()
 
         try:
-            async with asyncio.timeout(SHUTDOWN_TIMEOUT):
+            async with asyncio.timeout(SHUTDOWN_TIMEOUT_SECONDS):
                 await server.wait_closed()
         except TimeoutError:
             logger.warning(
                 "Shutdown timed out after %.0fs"
                 " — connections may not have closed cleanly",
-                SHUTDOWN_TIMEOUT,
+                SHUTDOWN_TIMEOUT_SECONDS,
             )
 
     logger.info("Server shutdown complete")
index 8ae4699f85313b257cdd8ea2f85f15a64c3a44a7..2a55cc2bbb7cc44491b29f14bfaacf99b7268cf2 100644 (file)
@@ -43,7 +43,7 @@ from ocpp.v201.enums import (
 )
 
 from server import (
-    DEFAULT_HEARTBEAT_INTERVAL,
+    DEFAULT_HEARTBEAT_INTERVAL_SECONDS,
     DEFAULT_TOTAL_COST,
     FALLBACK_TRANSACTION_ID,
     MAX_REQUEST_ID,
@@ -439,7 +439,7 @@ class TestBootNotificationHandler:
             reason="PowerUp",
         )
         assert response.status == RegistrationStatusEnumType.accepted
-        assert response.interval == DEFAULT_HEARTBEAT_INTERVAL
+        assert response.interval == DEFAULT_HEARTBEAT_INTERVAL_SECONDS
         assert isinstance(response.current_time, str)
         assert "T" in response.current_time
 
@@ -544,7 +544,7 @@ class TestBootNotificationHandler:
             reason="PowerUp",
         )
         assert response.status == RegistrationStatusEnumType.accepted
-        assert response.interval == DEFAULT_HEARTBEAT_INTERVAL
+        assert response.interval == DEFAULT_HEARTBEAT_INTERVAL_SECONDS
 
 
 class TestHeartbeatHandler:
index 0bcfc609bd8446261c497735841572b3cb3f2c8a..6eb0816fde7a483283c1848775a72dcdcc5d0f3b 100644 (file)
@@ -1,7 +1,7 @@
 <template>
   <router-view />
   <Container
-    v-show="$route.name !== 'charging-stations' && $route.name !== 'not-found'"
+    v-show="$route.name !== ROUTE_NAMES.CHARGING_STATIONS && $route.name !== ROUTE_NAMES.NOT_FOUND"
     id="action-container"
     class="action-container"
   >
@@ -11,6 +11,7 @@
 
 <script setup lang="ts">
 import Container from '@/components/Container.vue'
+import { ROUTE_NAMES } from '@/composables'
 </script>
 
 <style scoped>
index d756ef3cd4686b47214d5783ef55361d2645c092..3597e3c49da3ffea6500267b26150d8e6ff3deea 100644 (file)
@@ -99,7 +99,7 @@
           })
           .finally(() => {
             resetToggleButtonState('add-charging-stations', true)
-            $router.push({ name: 'charging-stations' })
+            $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
           })
           .catch((error: Error) => {
             $toast.error('Error at adding charging stations')
@@ -122,6 +122,7 @@ import {
   convertToBoolean,
   randomUUID,
   resetToggleButtonState,
+  ROUTE_NAMES,
   useTemplates,
   useUIClient,
 } from '@/composables'
index 045ccc74f0e684b95276c5fbd26f4dbdbccb03f5..c3ec902c4b2eadc747a90485ec9cd68dc212278e 100644 (file)
@@ -24,7 +24,7 @@
           })
           .finally(() => {
             resetToggleButtonState(`${props.hashId}-set-supervision-url`, true)
-            $router.push({ name: 'charging-stations' })
+            $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
           })
           .catch((error: Error) => {
             $toast.error('Error at setting supervision url')
@@ -41,7 +41,7 @@
 import { ref } from 'vue'
 
 import Button from '@/components/buttons/Button.vue'
-import { resetToggleButtonState, useUIClient } from '@/composables'
+import { resetToggleButtonState, ROUTE_NAMES, useUIClient } from '@/composables'
 
 const props = defineProps<{
   chargingStationId: string
index be35e2d2324a4326b8201150038cb30196ffb3ab..896641ffbc0b564570616f671e88ba74fac3e1db 100644 (file)
@@ -42,7 +42,13 @@ import { useRoute, useRouter } from 'vue-router'
 import { useToast } from 'vue-toast-notification'
 
 import Button from '@/components/buttons/Button.vue'
-import { convertToInt, resetToggleButtonState, UIClient, useUIClient } from '@/composables'
+import {
+  convertToInt,
+  resetToggleButtonState,
+  ROUTE_NAMES,
+  UIClient,
+  useUIClient,
+} from '@/composables'
 import { type OCPPVersion } from '@/types'
 
 const props = defineProps<{
@@ -86,7 +92,7 @@ const handleStartTransaction = async (): Promise<void> => {
       $toast.error('Error at authorizing RFID tag')
       console.error('Error at authorizing RFID tag:', error)
       resetToggleButtonState(toggleButtonId.value, true)
-      $router.push({ name: 'charging-stations' })
+      $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
       return
     }
   }
@@ -104,7 +110,7 @@ const handleStartTransaction = async (): Promise<void> => {
     console.error('Error at starting transaction:', error)
   } finally {
     resetToggleButtonState(toggleButtonId.value, true)
-    $router.push({ name: 'charging-stations' })
+    $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
   }
 }
 </script>
index 2324a1aae7be14981b8048ad36128c37fc98128e..b49a49b4af2045407dfd2fc7479268ced2a53a58 100644 (file)
@@ -4,7 +4,7 @@
       {{ evseId != null ? `${evseId}/${connectorId}` : connectorId }}
     </td>
     <td class="connectors-table__column">
-      {{ connector.status ?? 'Ø' }}
+      {{ connector.status ?? EMPTY_VALUE_PLACEHOLDER }}
     </td>
     <td class="connectors-table__column">
       {{ connector.locked === true ? 'Yes' : 'No' }}
         :id="`${hashId}-${evseId ?? 0}-${connectorId}-start-transaction`"
         :off="
           () => {
-            $router.push({ name: 'charging-stations' })
+            $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
           }
         "
         :on="
           () => {
             $router.push({
-              name: 'start-transaction',
+              name: ROUTE_NAMES.START_TRANSACTION,
               params: { hashId, chargingStationId, connectorId },
               query: {
                 ...(evseId != null ? { evseId: String(evseId) } : {}),
@@ -73,7 +73,7 @@ import type { ConnectorStatus, OCPPVersion, Status } from '@/types'
 import Button from '@/components/buttons/Button.vue'
 import StateButton from '@/components/buttons/StateButton.vue'
 import ToggleButton from '@/components/buttons/ToggleButton.vue'
-import { useExecuteAction, useUIClient } from '@/composables'
+import { EMPTY_VALUE_PLACEHOLDER, ROUTE_NAMES, useExecuteAction, useUIClient } from '@/composables'
 
 const props = defineProps<{
   atgStatus?: Status
index d9430a5a321daa71a4754030f658098943958da5..f77c767a66378f1776426505fae06492d508083b 100644 (file)
       {{ getWebSocketStateName(chargingStation.wsState) }}
     </td>
     <td class="cs-table__column">
-      {{ chargingStation.bootNotificationResponse?.status ?? 'Ø' }}
+      {{ chargingStation.bootNotificationResponse?.status ?? EMPTY_VALUE_PLACEHOLDER }}
     </td>
     <td class="cs-table__column">
-      {{ chargingStation.stationInfo.ocppVersion ?? 'Ø' }}
+      {{ chargingStation.stationInfo.ocppVersion ?? EMPTY_VALUE_PLACEHOLDER }}
     </td>
     <td class="cs-table__column">
       {{ chargingStation.stationInfo.templateName }}
@@ -28,7 +28,7 @@
       {{ chargingStation.stationInfo.chargePointModel }}
     </td>
     <td class="cs-table__column">
-      {{ chargingStation.stationInfo.firmwareVersion ?? 'Ø' }}
+      {{ chargingStation.stationInfo.firmwareVersion ?? EMPTY_VALUE_PLACEHOLDER }}
     </td>
     <td class="cs-table__column">
       <StateButton
         :id="`${chargingStation.stationInfo.hashId}-set-supervision-url`"
         :off="
           () => {
-            $router.push({ name: 'charging-stations' })
+            $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
           }
         "
         :on="
           () => {
             $router.push({
-              name: 'set-supervision-url',
+              name: ROUTE_NAMES.SET_SUPERVISION_URL,
               params: {
                 hashId: chargingStation.stationInfo.hashId,
                 chargingStationId: chargingStation.stationInfo.chargingStationId,
@@ -145,7 +145,9 @@ import ToggleButton from '@/components/buttons/ToggleButton.vue'
 import CSConnector from '@/components/charging-stations/CSConnector.vue'
 import {
   deleteLocalStorageByKeyPattern,
+  EMPTY_VALUE_PLACEHOLDER,
   getWebSocketStateName,
+  ROUTE_NAMES,
   useExecuteAction,
   useUIClient,
 } from '@/composables'
index 152907cc9855d2ddd20cfc8da9e562dff2ca653c..18e18ea685102fe6a11140b39c846674e8612bdc 100644 (file)
@@ -1,5 +1,15 @@
 // Local UI project constants
 
+export const EMPTY_VALUE_PLACEHOLDER = 'Ø'
+
+export const ROUTE_NAMES = {
+  ADD_CHARGING_STATIONS: 'add-charging-stations',
+  CHARGING_STATIONS: 'charging-stations',
+  NOT_FOUND: 'not-found',
+  SET_SUPERVISION_URL: 'set-supervision-url',
+  START_TRANSACTION: 'start-transaction',
+} as const
+
 export const SHARED_TOGGLE_BUTTON_KEY_PREFIX = 'shared-toggle-button-'
 export const TOGGLE_BUTTON_KEY_PREFIX = 'toggle-button-'
 export const UI_SERVER_CONFIGURATION_INDEX_KEY = 'uiServerConfigurationIndex'
index a9543fa79f0d6937db7b41994c1bcfb7aee2ef58..89c171c824adfba41de21225eca70706c5442d93 100644 (file)
@@ -1,4 +1,6 @@
 export {
+  EMPTY_VALUE_PLACEHOLDER,
+  ROUTE_NAMES,
   SHARED_TOGGLE_BUTTON_KEY_PREFIX,
   TOGGLE_BUTTON_KEY_PREFIX,
   UI_SERVER_CONFIGURATION_INDEX_KEY,
index d9fcfc9b1a71d85d2b948100e896e440ecea1203..e921c64b94063cb8db5657fb0fcab10ef3860b0c 100644 (file)
@@ -10,6 +10,7 @@ import {
   getFromLocalStorage,
   setToLocalStorage,
   templatesKey,
+  UI_SERVER_CONFIGURATION_INDEX_KEY,
   UIClient,
   uiClientKey,
 } from '@/composables'
@@ -45,15 +46,15 @@ const initializeApp = async (app: AppType, config: ConfigurationData): Promise<v
   const templates = ref<string[]>([])
   const chargingStations = ref<ChargingStationData[]>([])
   if (
-    getFromLocalStorage<number | undefined>('uiServerConfigurationIndex', undefined) == null ||
-    getFromLocalStorage('uiServerConfigurationIndex', 0) >
+    getFromLocalStorage<number | undefined>(UI_SERVER_CONFIGURATION_INDEX_KEY, undefined) == null ||
+    getFromLocalStorage(UI_SERVER_CONFIGURATION_INDEX_KEY, 0) >
       (configuration.value.uiServer as UIServerConfigurationSection[]).length - 1
   ) {
-    setToLocalStorage('uiServerConfigurationIndex', 0)
+    setToLocalStorage(UI_SERVER_CONFIGURATION_INDEX_KEY, 0)
   }
   const uiClient = UIClient.getInstance(
     (configuration.value.uiServer as UIServerConfigurationSection[])[
-      getFromLocalStorage('uiServerConfigurationIndex', 0)
+      getFromLocalStorage(UI_SERVER_CONFIGURATION_INDEX_KEY, 0)
     ]
   )
   app.provide(configurationKey, configuration)
index a3eb54d177c6bc56f9ee43688b60bf74015b783b..adf84665711d0fb980d4d7122bf428fbbf2539b8 100644 (file)
@@ -4,6 +4,7 @@ import { createRouter, createWebHistory } from 'vue-router'
 import AddChargingStations from '@/components/actions/AddChargingStations.vue'
 import SetSupervisionUrl from '@/components/actions/SetSupervisionUrl.vue'
 import StartTransaction from '@/components/actions/StartTransaction.vue'
+import { ROUTE_NAMES } from '@/composables'
 import ChargingStationsView from '@/views/ChargingStationsView.vue'
 import NotFoundView from '@/views/NotFoundView.vue'
 
@@ -14,7 +15,7 @@ export const router = createRouter({
       components: {
         default: ChargingStationsView,
       },
-      name: 'charging-stations',
+      name: ROUTE_NAMES.CHARGING_STATIONS,
       path: '/',
     },
     {
@@ -22,7 +23,7 @@ export const router = createRouter({
         action: AddChargingStations,
         default: ChargingStationsView,
       },
-      name: 'add-charging-stations',
+      name: ROUTE_NAMES.ADD_CHARGING_STATIONS,
       path: '/add-charging-stations',
     },
     {
@@ -30,7 +31,7 @@ export const router = createRouter({
         action: SetSupervisionUrl,
         default: ChargingStationsView,
       },
-      name: 'set-supervision-url',
+      name: ROUTE_NAMES.SET_SUPERVISION_URL,
       path: '/set-supervision-url/:hashId/:chargingStationId',
       props: { action: true, default: false },
     },
@@ -39,7 +40,7 @@ export const router = createRouter({
         action: StartTransaction,
         default: ChargingStationsView,
       },
-      name: 'start-transaction',
+      name: ROUTE_NAMES.START_TRANSACTION,
       path: '/start-transaction/:hashId/:chargingStationId/:connectorId',
       props: { action: true, default: false },
     },
@@ -47,7 +48,7 @@ export const router = createRouter({
       components: {
         default: NotFoundView,
       },
-      name: 'not-found',
+      name: ROUTE_NAMES.NOT_FOUND,
       path: '/:pathMatch(.*)*',
     },
   ],
index 6e5e5a70fc4d205744c1ce11229d4e40bbc46596..aeb9df66aa13e8d5c37350ae99523d2d0a741289 100644 (file)
@@ -29,8 +29,8 @@
                     )
                     clearToggleButtons()
                     refresh()
-                    $route.name !== 'charging-stations' &&
-                      $router.push({ name: 'charging-stations' })
+                    $route.name !== ROUTE_NAMES.CHARGING_STATIONS &&
+                      $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
                   },
                   { once: true }
                 )
         :key="state.renderAddChargingStations"
         :off="
           () => {
-            $router.push({ name: 'charging-stations' })
+            $router.push({ name: ROUTE_NAMES.CHARGING_STATIONS })
           }
         "
         :on="
           () => {
-            $router.push({ name: 'add-charging-stations' })
+            $router.push({ name: ROUTE_NAMES.ADD_CHARGING_STATIONS })
           }
         "
         :shared="true"
@@ -123,7 +123,9 @@ import {
   deleteLocalStorageByKeyPattern,
   getFromLocalStorage,
   randomUUID,
+  ROUTE_NAMES,
   setToLocalStorage,
+  TOGGLE_BUTTON_KEY_PREFIX,
   UI_SERVER_CONFIGURATION_INDEX_KEY,
   useChargingStations,
   useConfiguration,
@@ -162,7 +164,7 @@ const refresh = (): void => {
 }
 
 const clearToggleButtons = (): void => {
-  deleteLocalStorageByKeyPattern('toggle-button')
+  deleteLocalStorageByKeyPattern(TOGGLE_BUTTON_KEY_PREFIX)
 }
 
 const $configuration = useConfiguration()