From: Daniel <7558512+DerGenaue@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:50:28 +0000 (+0200) Subject: feat(ui-server): allow override of station identity and CSMS credentials in addChargi... X-Git-Tag: cli@v4.5.0~10 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=f23ba158a146ac3a0aedd85195c16e4d4595acd9;p=e-mobility-charging-stations-simulator.git feat(ui-server): allow override of station identity and CSMS credentials in addChargingStations (#1802) * feat(ui-server): allow per-call override of station identity and CSMS credentials Extend ChargingStationOptions with baseName, fixedName, nameSuffix, supervisionUser and supervisionPassword so that callers of the addChargingStations UI procedure can fully customise a station without editing template files. Identity derivation (chargingStationId, hashId) moves to the tail of getStationInfo, after setChargingStationOptions runs, so the merged stationInfo is the single source of truth for baseName/fixedName/nameSuffix. getChargingStationId now accepts a narrow StationIdentity pick that both ChargingStationTemplate and ChargingStationInfo satisfy; getHashId grows an optional chargingStationIdOverride so the new identity flows through without altering the hashed payload shape for existing callers. Default behaviour is unchanged: hash ID regression test pins the pre-existing hash, and omitted options leave stationInfo untouched. * docs(ui-server): sync ChargingStationOptions docs with source interface Bring the README protocol reference, the MCP zod schema and the web UI ChargingStationOptions type back in sync with src/types/ChargingStationWorker.ts. Covers the newly added baseName, fixedName, nameSuffix, supervisionUser and supervisionPassword fields, plus previously missing fields not yet surfaced in the public docs. * feat(ui-web): expose baseName, fixedName and CSMS credentials in add-station dialog Surface the new addChargingStations options on the web UI form: a base name text field, an "append counter to name" checkbox that controls fixedName, and a supervision user/password pair alongside the existing supervision URL. Empty fields are omitted from the payload so the template defaults apply unchanged.  Conflicts:  ui/web/src/components/actions/AddChargingStations.vue * feat(ui-server): allow setSupervisionUrl to update CSMS credentials Extend the setSupervisionUrl UI procedure so callers can update the supervision WebSocket's basic auth user and password on an already running station, not only the URL. All three fields (url, supervisionUser, supervisionPassword) become optional; the handler now requires at least one to be set. ChargingStation.setSupervisionUrl accepts the three optional arguments and writes the non-URL fields onto stationInfo via saveStationInfo. Changes take effect on the next WebSocket (re)connect, mirroring how URL updates already worked. The MCP zod schema and the protocol reference in the README are updated accordingly. * feat(ui-web): expose CSMS credentials in set-supervision dialog Surface the extended setSupervisionUrl procedure on the web UI: user and password inputs next to the existing URL field, a client-side guard that requires at least one field set, and a renamed form header ("Set Supervision") that matches the broader scope. UIClient passes the new fields through only when populated, so existing URL-only callers are unaffected. * fix(ui-web): serve index.html as SPA fallback so deep-linked routes survive reload The built bundle is served by start.js via serve-static, which 404s on any path that isn't a physical file — so refreshing a router route like /add-charging-stations or /set-supervision-url/... produced "Cannot GET ...". When serve-static gives up, fall back to sending the bundled index.html with 200 OK so the SPA router can resolve the route client-side. POST/PUT/etc. still fall through to finalhandler. * [autofix.ci] apply automated fixes * test(ui-web): update AddChargingStations tests for new fields Bump checkbox count to 5 (appendCounter added) and cover baseName, supervision credential pass-through and fixedName behaviour. * fix: PR comments * fix: PR comments - server: setSupervisionUrl: url required, supervisionUser/supervisionPassword independent (string updates incl. "" to clear, undefined preserves); drop block-comment noise; align README and MCP schema descriptions - ui: SetSupervisionUrl dialog: always send credentials verbatim — empty fields clear stored credentials (frontend can't distinguish null vs empty) - ui: AddChargingStations dialog: replace inverted appendCounter with fixedName mirroring the API field; label "(base name is full station name)"; empty fields keep preserving template defaults - server: Rename StationIdentity → ChargingStationNameTemplate (and the parameter in getChargingStationId) so the type name reflects its role as the building blocks of chargingStationId - Tests updated to match the new semantics * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- diff --git a/README.md b/README.md index fee0ed45..afc3c372 100644 --- a/README.md +++ b/README.md @@ -1016,13 +1016,18 @@ Set the WebSocket header _Sec-WebSocket-Protocol_ to `ui0.0.1`. `template`: string, `numberOfStations`: number, `options?`: { - `supervisionUrls?`: string | string[], - `persistentConfiguration?`: boolean, - `autoStart?`: boolean, `autoRegister?`: boolean, + `autoStart?`: boolean, + `baseName?`: string, `enableStatistics?`: boolean, + `fixedName?`: boolean, + `nameSuffix?`: string, `ocppStrictCompliance?`: boolean, - `stopTransactionsOnStopped?`: boolean + `persistentConfiguration?`: boolean, + `stopTransactionsOnStopped?`: boolean, + `supervisionPassword?`: string, + `supervisionUrls?`: string | string[], + `supervisionUser?`: string } } @@ -1056,8 +1061,11 @@ Set the WebSocket header _Sec-WebSocket-Protocol_ to `ui0.0.1`. `ProcedureName`: 'setSupervisionUrl' `PDU`: { `hashIds`: charging station unique identifier strings array (optional, default: all charging stations), - `url`: string - } + `url`: string, + `supervisionUser?`: string, + `supervisionPassword?`: string + } + `url` is required. `supervisionUser` and `supervisionPassword` are each optional and independent: a string (including `""`, which clears the field) updates the value; omitting the field preserves the existing value. Changes take effect on the next WebSocket (re)connect. - Response: `PDU`: { diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index b36e4ba8..170f376d 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -993,10 +993,16 @@ export class ChargingStation extends EventEmitter { } /** - * Updates the supervision server URL in configuration or station info. + * Updates the supervision server URL and optionally the CSMS basic auth credentials in configuration or station info. * @param url - The new supervision server URL + * @param supervisionUser - The new CSMS basic auth user (optional; "" clears, undefined preserves) + * @param supervisionPassword - The new CSMS basic auth password (optional; "" clears, undefined preserves) */ - public setSupervisionUrl (url: string): void { + public setSupervisionUrl ( + url: string, + supervisionUser?: string, + supervisionPassword?: string + ): void { if ( this.stationInfo?.supervisionUrlOcppConfiguration === true && isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) @@ -1007,6 +1013,16 @@ export class ChargingStation extends EventEmitter { this.configuredSupervisionUrl = this.getConfiguredSupervisionUrl() this.saveStationInfo() } + if (this.stationInfo != null && (supervisionUser != null || supervisionPassword != null)) { + if (supervisionUser != null) { + this.stationInfo.supervisionUser = supervisionUser + } + if (supervisionPassword != null) { + this.stationInfo.supervisionPassword = supervisionPassword + } + this.saveStationInfo() + this.emitChargingStationEvent(ChargingStationEvents.updated) + } } /** Starts the charging station, initializes connectors, and connects to the central server. */ @@ -1490,7 +1506,8 @@ export class ChargingStation extends EventEmitter { } private getStationInfo (options?: ChargingStationOptions): ChargingStationInfo { - const stationInfoFromTemplate = this.getStationInfoFromTemplate() + const { stationInfo: stationInfoFromTemplate, stationTemplate } = + this.getStationInfoFromTemplate() options?.persistentConfiguration != null && (stationInfoFromTemplate.stationInfoPersistentConfiguration = options.persistentConfiguration) const stationInfoFromFile = this.getStationInfoFromFile( @@ -1508,12 +1525,15 @@ export class ChargingStation extends EventEmitter { } else { stationInfo = stationInfoFromTemplate stationInfoFromFile != null && - propagateSerialNumber(this.getTemplateFromFile(), stationInfoFromFile, stationInfo) + propagateSerialNumber(stationTemplate, stationInfoFromFile, stationInfo) } - return setChargingStationOptions( + stationInfo = setChargingStationOptions( mergeDeepRight(Constants.DEFAULT_STATION_INFO as ChargingStationInfo, stationInfo), options ) + stationInfo.chargingStationId = getChargingStationId(this.index, stationInfo) + stationInfo.hashId = getHashId(this.index, stationTemplate, stationInfo.chargingStationId) + return stationInfo } private getStationInfoFromFile ( @@ -1536,7 +1556,10 @@ export class ChargingStation extends EventEmitter { return stationInfo } - private getStationInfoFromTemplate (): ChargingStationInfo { + private getStationInfoFromTemplate (): { + stationInfo: ChargingStationInfo + stationTemplate: ChargingStationTemplate + } { const stationTemplate = this.getTemplateFromFile() if (stationTemplate == null) { const errorMsg = `Failed to read charging station template file ${this.templateFile}` @@ -1553,10 +1576,11 @@ export class ChargingStation extends EventEmitter { checkEvsesConfiguration(stationTemplate, this.logPrefix(), this.templateFile) } const stationInfo = stationTemplateToStationInfo(stationTemplate) - stationInfo.hashId = getHashId(this.index, stationTemplate) + // hashId and chargingStationId are intentionally not set here. They are derived + // at the end of getStationInfo() so that any identity overrides coming from + // ChargingStationOptions (baseName, fixedName, nameSuffix) are honoured. stationInfo.templateIndex = this.index stationInfo.templateName = buildTemplateName(this.templateFile) - stationInfo.chargingStationId = getChargingStationId(this.index, stationTemplate) createSerialNumber(stationTemplate, stationInfo) stationInfo.voltageOut = this.getVoltageOut(stationInfo) if (isNotEmptyArray(stationTemplate.power)) { @@ -1586,7 +1610,7 @@ export class ChargingStation extends EventEmitter { if (stationTemplate.resetTime != null) { stationInfo.resetTime = secondsToMilliseconds(stationTemplate.resetTime) } - return stationInfo + return { stationInfo, stationTemplate } } private getTemplateFromFile (): ChargingStationTemplate | undefined { diff --git a/src/charging-station/Helpers.ts b/src/charging-station/Helpers.ts index 57d73f5c..e75341e5 100644 --- a/src/charging-station/Helpers.ts +++ b/src/charging-station/Helpers.ts @@ -81,20 +81,25 @@ export const buildTemplateName = (templateFile: string): string => { return join(templateFileParsedPath.dir, templateFileParsedPath.name) } +export type ChargingStationNameTemplate = Pick< + ChargingStationTemplate, + 'baseName' | 'fixedName' | 'nameSuffix' +> + export const getChargingStationId = ( index: number, - stationTemplate: ChargingStationTemplate | undefined + nameTemplate: ChargingStationNameTemplate | undefined ): string => { - if (stationTemplate == null) { + if (nameTemplate == null) { return "Unknown 'chargingStationId'" } // In case of multiple instances: add instance index to charging station id const instanceIndex = env.CF_INSTANCE_INDEX ?? 0 - const idSuffix = stationTemplate.nameSuffix ?? '' + const idSuffix = nameTemplate.nameSuffix ?? '' const idStr = `000000000${index.toString()}` - return stationTemplate.fixedName === true - ? stationTemplate.baseName - : `${stationTemplate.baseName}-${instanceIndex.toString()}${idStr.substring( + return nameTemplate.fixedName === true + ? nameTemplate.baseName + : `${nameTemplate.baseName}-${instanceIndex.toString()}${idStr.substring( idStr.length - 4 )}${idSuffix}` } @@ -156,7 +161,11 @@ export const removeExpiredReservations = async ( } } -export const getHashId = (index: number, stationTemplate: ChargingStationTemplate): string => { +export const getHashId = ( + index: number, + stationTemplate: ChargingStationTemplate, + chargingStationIdOverride?: string +): string => { const chargingStationInfo = { chargePointModel: stationTemplate.chargePointModel, chargePointVendor: stationTemplate.chargePointVendor, @@ -175,7 +184,9 @@ export const getHashId = (index: number, stationTemplate: ChargingStationTemplat } return hash( Constants.DEFAULT_HASH_ALGORITHM, - `${JSON.stringify(chargingStationInfo)}${getChargingStationId(index, stationTemplate)}`, + `${JSON.stringify(chargingStationInfo)}${ + chargingStationIdOverride ?? getChargingStationId(index, stationTemplate) + }`, 'hex' ) } @@ -428,6 +439,12 @@ export const setChargingStationOptions = ( if (options?.supervisionUrls != null) { stationInfo.supervisionUrls = options.supervisionUrls } + if (options?.supervisionUser != null) { + stationInfo.supervisionUser = options.supervisionUser + } + if (options?.supervisionPassword != null) { + stationInfo.supervisionPassword = options.supervisionPassword + } if (options?.persistentConfiguration != null) { stationInfo.stationInfoPersistentConfiguration = options.persistentConfiguration stationInfo.ocppPersistentConfiguration = options.persistentConfiguration @@ -449,6 +466,15 @@ export const setChargingStationOptions = ( if (options?.stopTransactionsOnStopped != null) { stationInfo.stopTransactionsOnStopped = options.stopTransactionsOnStopped } + if (options?.baseName != null) { + stationInfo.baseName = options.baseName + } + if (options?.fixedName != null) { + stationInfo.fixedName = options.fixedName + } + if (options?.nameSuffix != null) { + stationInfo.nameSuffix = options.nameSuffix + } return stationInfo } diff --git a/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts b/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts index b2533aa1..95b14718 100644 --- a/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts +++ b/src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts @@ -189,7 +189,13 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: 'url' field is required` ) } - this.chargingStation.setSupervisionUrl(url) + const supervisionUser = requestPayload?.supervisionUser + const supervisionPassword = requestPayload?.supervisionPassword + this.chargingStation.setSupervisionUrl( + url, + typeof supervisionUser === 'string' ? supervisionUser : undefined, + typeof supervisionPassword === 'string' ? supervisionPassword : undefined + ) }, ], [ diff --git a/src/charging-station/ui-server/mcp/MCPToolSchemas.ts b/src/charging-station/ui-server/mcp/MCPToolSchemas.ts index 3438b73e..703cabf4 100644 --- a/src/charging-station/ui-server/mcp/MCPToolSchemas.ts +++ b/src/charging-station/ui-server/mcp/MCPToolSchemas.ts @@ -32,7 +32,19 @@ const emptyInputSchema = z.object({}) const chargingStationOptionsSchema = z.object({ autoRegister: z.boolean().optional().describe('Set stations as registered at boot notification'), autoStart: z.boolean().optional().describe('Enable automatic start of added charging station'), + baseName: z + .string() + .optional() + .describe('Override the template base name used to derive the chargingStationId'), enableStatistics: z.boolean().optional().describe('Enable charging station statistics'), + fixedName: z + .boolean() + .optional() + .describe('Use baseName verbatim as chargingStationId instead of appending index/suffix'), + nameSuffix: z + .string() + .optional() + .describe('Suffix appended to the derived chargingStationId (ignored when fixedName is true)'), ocppStrictCompliance: z .boolean() .optional() @@ -45,10 +57,18 @@ const chargingStationOptionsSchema = z.object({ .boolean() .optional() .describe('Enable stop transactions on station stop'), + supervisionPassword: z + .string() + .optional() + .describe('CSMS basic auth password used on the supervision WebSocket'), supervisionUrls: z .union([z.url(), z.array(z.url())]) .optional() .describe('OCPP server supervision URL(s)'), + supervisionUser: z + .string() + .optional() + .describe('CSMS basic auth user used on the supervision WebSocket'), }) /** Maps ProcedureName to OCPP JSON Schema file base names per version */ @@ -317,9 +337,18 @@ export const mcpToolSchemas = new Map([ [ ProcedureName.SET_SUPERVISION_URL, { - description: 'Set the OCPP server supervision URL for one or more charging stations', + description: + 'Set the OCPP server supervision URL for one or more charging stations. Optionally updates the CSMS basic auth credentials (empty string clears a credential, undefined preserves it).', inputSchema: z.object({ hashIds, + supervisionPassword: z + .string() + .optional() + .describe('CSMS basic auth password (empty string clears)'), + supervisionUser: z + .string() + .optional() + .describe('CSMS basic auth user (empty string clears)'), url: z.url().describe('The OCPP server supervision URL to set'), }), }, diff --git a/src/types/ChargingStationWorker.ts b/src/types/ChargingStationWorker.ts index 551c1f70..b1ee7b04 100644 --- a/src/types/ChargingStationWorker.ts +++ b/src/types/ChargingStationWorker.ts @@ -50,11 +50,16 @@ export interface ChargingStationData extends WorkerData { export interface ChargingStationOptions extends JsonObject { autoRegister?: boolean autoStart?: boolean + baseName?: string enableStatistics?: boolean + fixedName?: boolean + nameSuffix?: string ocppStrictCompliance?: boolean persistentConfiguration?: boolean stopTransactionsOnStopped?: boolean + supervisionPassword?: string supervisionUrls?: string | string[] + supervisionUser?: string } export interface ChargingStationWorkerData extends WorkerData { diff --git a/tests/charging-station/Helpers.test.ts b/tests/charging-station/Helpers.test.ts index 8b45004d..22f7eefd 100644 --- a/tests/charging-station/Helpers.test.ts +++ b/tests/charging-station/Helpers.test.ts @@ -20,6 +20,7 @@ import { hasPendingReservations, hasReservationExpired, resetConnectorStatus, + setChargingStationOptions, validateStationInfo, } from '../../src/charging-station/Helpers.js' import { @@ -28,6 +29,7 @@ import { ChargingProfilePurposeType, type ChargingStationConfiguration, type ChargingStationInfo, + type ChargingStationOptions, type ChargingStationTemplate, type ConnectorStatus, ConnectorStatusEnum, @@ -78,6 +80,117 @@ await describe('Helpers', async () => { ) }) + await it('should return baseName verbatim when fixedName is true', () => { + const template = { + baseName: 'DYNAMIC-STATION', + fixedName: true, + } satisfies Partial + assert.strictEqual( + getChargingStationId(1, template as ChargingStationTemplate), + 'DYNAMIC-STATION' + ) + }) + + await it('should append nameSuffix to the indexed id when fixedName is false', () => { + const template = { + baseName: 'CS', + fixedName: false, + nameSuffix: '-X', + } satisfies Partial + assert.strictEqual(getChargingStationId(7, template as ChargingStationTemplate), 'CS-00007-X') + }) + + await it('should derive charging station id from stationInfo identity fields', () => { + // stationInfo satisfies the ChargingStationNameTemplate shape since it inherits baseName / fixedName / nameSuffix from the template type. + const stationInfo = { + baseName: 'INFO-STATION', + fixedName: true, + } satisfies Partial + assert.strictEqual(getChargingStationId(1, stationInfo as ChargingStationInfo), 'INFO-STATION') + }) + + await it('should honour chargingStationId override in getHashId', () => { + const hashWithoutOverride = getHashId(1, chargingStationTemplate) + const hashWithOverride = getHashId(1, chargingStationTemplate, 'OVERRIDDEN-ID') + assert.notStrictEqual(hashWithoutOverride, hashWithOverride) + // Passing the default-derived id explicitly must reproduce the default hash. + assert.strictEqual( + getHashId(1, chargingStationTemplate, getChargingStationId(1, chargingStationTemplate)), + hashWithoutOverride + ) + }) + + await it('should produce distinct hash ids when identity options differ', () => { + const baseId = getChargingStationId(1, chargingStationTemplate) + const overriddenId = getChargingStationId(1, { + ...chargingStationTemplate, + baseName: 'OTHER', + }) + assert.notStrictEqual( + getHashId(1, chargingStationTemplate, baseId), + getHashId(1, chargingStationTemplate, overriddenId) + ) + }) + + await describe('setChargingStationOptions', async () => { + const buildStationInfo = (): ChargingStationInfo => + ({ + baseName: TEST_CHARGING_STATION_BASE_NAME, + hashId: 'placeholder', + templateIndex: 0, + templateName: 'test-template', + }) as ChargingStationInfo + + await it('should return stationInfo unchanged when options are undefined', () => { + const stationInfo = buildStationInfo() + const before = { ...stationInfo } + const result = setChargingStationOptions(stationInfo) + assert.deepStrictEqual(result, before) + }) + + await it('should apply baseName override', () => { + const options: ChargingStationOptions = { baseName: 'DYNAMIC' } + const result = setChargingStationOptions(buildStationInfo(), options) + assert.strictEqual(result.baseName, 'DYNAMIC') + }) + + await it('should apply fixedName override', () => { + const options: ChargingStationOptions = { fixedName: true } + const result = setChargingStationOptions(buildStationInfo(), options) + assert.strictEqual(result.fixedName, true) + }) + + await it('should apply nameSuffix override', () => { + const options: ChargingStationOptions = { nameSuffix: '-SUFFIX' } + const result = setChargingStationOptions(buildStationInfo(), options) + assert.strictEqual(result.nameSuffix, '-SUFFIX') + }) + + await it('should apply supervisionUser override', () => { + const options: ChargingStationOptions = { supervisionUser: 'alice' } + const result = setChargingStationOptions(buildStationInfo(), options) + assert.strictEqual(result.supervisionUser, 'alice') + }) + + await it('should apply supervisionPassword override', () => { + const options: ChargingStationOptions = { supervisionPassword: 'secret' } + const result = setChargingStationOptions(buildStationInfo(), options) + assert.strictEqual(result.supervisionPassword, 'secret') + }) + + await it('should not overwrite stationInfo fields when option value is undefined', () => { + const stationInfo = buildStationInfo() + stationInfo.baseName = 'KEEP-ME' + stationInfo.supervisionUser = 'original' + const result = setChargingStationOptions(stationInfo, { + autoStart: true, + }) + assert.strictEqual(result.baseName, 'KEEP-ME') + assert.strictEqual(result.supervisionUser, 'original') + assert.strictEqual(result.autoStart, true) + }) + }) + await it('should throw when stationInfo is missing', () => { // Arrange // For validation edge cases, we need to manually create invalid states diff --git a/ui/common/src/types/ChargingStationType.ts b/ui/common/src/types/ChargingStationType.ts index c71f81cc..f149f1e6 100644 --- a/ui/common/src/types/ChargingStationType.ts +++ b/ui/common/src/types/ChargingStationType.ts @@ -257,11 +257,16 @@ export interface ChargingStationOcppConfiguration extends JsonObject { export interface ChargingStationOptions extends JsonObject { autoRegister?: boolean autoStart?: boolean + baseName?: string enableStatistics?: boolean + fixedName?: boolean + nameSuffix?: string ocppStrictCompliance?: boolean persistentConfiguration?: boolean stopTransactionsOnStopped?: boolean + supervisionPassword?: string supervisionUrls?: string | string[] + supervisionUser?: string } export interface ConfigurationKey extends OCPPConfigurationKey { diff --git a/ui/web/src/components/actions/AddChargingStations.vue b/ui/web/src/components/actions/AddChargingStations.vue index 1dafe567..dbd968bc 100644 --- a/ui/web/src/components/actions/AddChargingStations.vue +++ b/ui/web/src/components/actions/AddChargingStations.vue @@ -33,6 +33,24 @@ >

Template options overrides:

    +
  • + Base name: + + Fixed name (base name is full station name): + +
  • Supervision url:
  • +
  • + Supervision credentials: + + +
  • Auto start: ({ autoStart: false, + baseName: '', enableStatistics: false, + fixedName: false, numberOfStations: 1, ocppStrictCompliance: true, persistentConfiguration: true, renderTemplates: randomUUID(), + supervisionPassword: '', supervisionUrl: '', + supervisionUser: '', template: '', }) @@ -137,11 +183,18 @@ const addChargingStations = (): void => { executeAction( $uiClient.addChargingStations(state.value.template, state.value.numberOfStations, { autoStart: convertToBoolean(state.value.autoStart), + baseName: state.value.baseName.length > 0 ? state.value.baseName : undefined, enableStatistics: convertToBoolean(state.value.enableStatistics), + fixedName: + state.value.baseName.length > 0 ? convertToBoolean(state.value.fixedName) : undefined, ocppStrictCompliance: convertToBoolean(state.value.ocppStrictCompliance), persistentConfiguration: convertToBoolean(state.value.persistentConfiguration), + supervisionPassword: + state.value.supervisionPassword.length > 0 ? state.value.supervisionPassword : undefined, supervisionUrls: state.value.supervisionUrl.length > 0 ? state.value.supervisionUrl : undefined, + supervisionUser: + state.value.supervisionUser.length > 0 ? state.value.supervisionUser : undefined, }), 'Charging stations successfully added', 'Error at adding charging stations', @@ -162,8 +215,17 @@ const addChargingStations = (): void => { text-align: center; } +.supervision-url, +.base-name, +.supervision-user, +.supervision-password { + width: 100%; + max-width: 40rem; + text-align: left; +} + .template-options { - list-style: circle inside; + list-style: circle; text-align: left; } diff --git a/ui/web/src/components/actions/SetSupervisionUrl.vue b/ui/web/src/components/actions/SetSupervisionUrl.vue index 133e3fc6..e6dbbe16 100644 --- a/ui/web/src/components/actions/SetSupervisionUrl.vue +++ b/ui/web/src/components/actions/SetSupervisionUrl.vue @@ -3,7 +3,7 @@ Set Supervision Url

    {{ chargingStationId }}

    -

    Supervision Url:

    +

    Supervision url:

    +

    Supervision credentials:

    + +