From 240fa4da80fd262158004eb576410d02afe0001f Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 1 Mar 2024 20:09:01 +0100 Subject: [PATCH] feat(ui): use toggle button to star/stop simulator MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/charging-station/Bootstrap.ts | 6 ++ .../ocpp/1.6/OCPP16IncomingRequestService.ts | 2 +- .../ocpp/1.6/OCPP16ResponseService.ts | 2 +- .../ocpp/2.0/OCPP20IncomingRequestService.ts | 2 +- .../ocpp/2.0/OCPP20ResponseService.ts | 2 +- .../ui-services/AbstractUIService.ts | 18 ++++- src/types/UIProtocol.ts | 1 + .../src/components/buttons/ToggleButton.vue | 4 +- ui/web/src/composables/UIClient.ts | 4 ++ ui/web/src/types/UIProtocol.ts | 1 + ui/web/src/views/ChargingStationsView.vue | 68 +++++++++++++++---- 11 files changed, 89 insertions(+), 21 deletions(-) diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index 047b321b..9247ab3d 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -118,6 +118,12 @@ export class Bootstrap extends EventEmitter { ) } + public getState (): { started: boolean } { + return { + started: this.started + } + } + public getLastIndex (templateName: string): number { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const indexes = [...this.templatesChargingStations.get(templateName)!.indexes] diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index f77dfa7f..1456e237 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -643,7 +643,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { // Throw exception throw new OCPPError( ErrorType.NOT_IMPLEMENTED, - `${commandName} is not implemented to handle request PDU ${JSON.stringify( + `'${commandName}' is not implemented to handle request PDU ${JSON.stringify( commandPayload, undefined, 2 diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index 691bf0f6..3905445e 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -468,7 +468,7 @@ export class OCPP16ResponseService extends OCPPResponseService { // Throw exception throw new OCPPError( ErrorType.NOT_IMPLEMENTED, - `${commandName} is not implemented to handle response PDU ${JSON.stringify( + `'${commandName}' is not implemented to handle response PDU ${JSON.stringify( payload, undefined, 2 diff --git a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts index 32843895..2a561e45 100644 --- a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts @@ -109,7 +109,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { // Throw exception throw new OCPPError( ErrorType.NOT_IMPLEMENTED, - `${commandName} is not implemented to handle request PDU ${JSON.stringify( + `'${commandName}' is not implemented to handle request PDU ${JSON.stringify( commandPayload, undefined, 2 diff --git a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts index 09b319c9..9473324f 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts @@ -141,7 +141,7 @@ export class OCPP20ResponseService extends OCPPResponseService { // Throw exception throw new OCPPError( ErrorType.NOT_IMPLEMENTED, - `${commandName} is not implemented to handle response PDU ${JSON.stringify( + `'${commandName}' is not implemented to handle response PDU ${JSON.stringify( payload, undefined, 2 diff --git a/src/charging-station/ui-server/ui-services/AbstractUIService.ts b/src/charging-station/ui-server/ui-services/AbstractUIService.ts index fbca016b..de83c6b7 100644 --- a/src/charging-station/ui-server/ui-services/AbstractUIService.ts +++ b/src/charging-station/ui-server/ui-services/AbstractUIService.ts @@ -76,6 +76,7 @@ export abstract class AbstractUIService { [ProcedureName.LIST_CHARGING_STATIONS, this.handleListChargingStations.bind(this)], [ProcedureName.ADD_CHARGING_STATIONS, this.handleAddChargingStations.bind(this)], [ProcedureName.PERFORMANCE_STATISTICS, this.handlePerformanceStatistics.bind(this)], + [ProcedureName.SIMULATOR_STATE, this.handleSimulatorState.bind(this)], [ProcedureName.START_SIMULATOR, this.handleStartSimulator.bind(this)], [ProcedureName.STOP_SIMULATOR, this.handleStopSimulator.bind(this)] ]) @@ -98,7 +99,7 @@ export abstract class AbstractUIService { if (!this.requestHandlers.has(command)) { throw new BaseError( - `${command} is not implemented to handle message payload ${JSON.stringify( + `'${command}' is not implemented to handle message payload ${JSON.stringify( requestPayload, undefined, 2 @@ -295,6 +296,21 @@ export abstract class AbstractUIService { } } + private handleSimulatorState (): ResponsePayload { + try { + return { + status: ResponseStatus.SUCCESS, + state: Bootstrap.getInstance().getState() + } satisfies ResponsePayload + } catch (error) { + return { + status: ResponseStatus.FAILURE, + errorMessage: (error as Error).message, + errorStack: (error as Error).stack + } satisfies ResponsePayload + } + } + private async handleStartSimulator (): Promise { try { await Bootstrap.getInstance().start() diff --git a/src/types/UIProtocol.ts b/src/types/UIProtocol.ts index 6e120337..37ec8ba9 100644 --- a/src/types/UIProtocol.ts +++ b/src/types/UIProtocol.ts @@ -29,6 +29,7 @@ export type ProtocolRequestHandler = ( ) => undefined | Promise | ResponsePayload | Promise export enum ProcedureName { + SIMULATOR_STATE = 'simulatorState', START_SIMULATOR = 'startSimulator', STOP_SIMULATOR = 'stopSimulator', LIST_TEMPLATES = 'listTemplates', diff --git a/ui/web/src/components/buttons/ToggleButton.vue b/ui/web/src/components/buttons/ToggleButton.vue index dd1805ca..b1cab90c 100644 --- a/ui/web/src/components/buttons/ToggleButton.vue +++ b/ui/web/src/components/buttons/ToggleButton.vue @@ -15,6 +15,8 @@ const props = defineProps<{ shared?: boolean on?: () => void off?: () => void + onStyle?: string + offStyle?: string }>() const $emit = defineEmits(['clicked']) @@ -26,7 +28,7 @@ const state = ref({ }) const click = (): void => { - if (props.shared) { + if (props.shared === true) { for (const key in localStorage) { if (key !== id && key.startsWith('shared-toggle-button-')) { setToLocalStorage(key, false) diff --git a/ui/web/src/composables/UIClient.ts b/ui/web/src/composables/UIClient.ts index 023aef11..04b703e3 100644 --- a/ui/web/src/composables/UIClient.ts +++ b/ui/web/src/composables/UIClient.ts @@ -53,6 +53,10 @@ export class UIClient { this.ws?.addEventListener(event, listener, options) } + public async simulatorState(): Promise { + return this.sendRequest(ProcedureName.SIMULATOR_STATE, {}) + } + public async startSimulator(): Promise { return this.sendRequest(ProcedureName.START_SIMULATOR, {}) } diff --git a/ui/web/src/types/UIProtocol.ts b/ui/web/src/types/UIProtocol.ts index afc55b03..18309895 100644 --- a/ui/web/src/types/UIProtocol.ts +++ b/ui/web/src/types/UIProtocol.ts @@ -25,6 +25,7 @@ export type ProtocolRequestHandler = ( ) => ResponsePayload | Promise export enum ProcedureName { + SIMULATOR_STATE = 'simulatorState', START_SIMULATOR = 'startSimulator', STOP_SIMULATOR = 'stopSimulator', LIST_TEMPLATES = 'listTemplates', diff --git a/ui/web/src/views/ChargingStationsView.vue b/ui/web/src/views/ChargingStationsView.vue index c49449f6..57ae3e20 100644 --- a/ui/web/src/views/ChargingStationsView.vue +++ b/ui/web/src/views/ChargingStationsView.vue @@ -20,6 +20,7 @@ 'open', () => { setToLocalStorage('uiServerConfigurationIndex', state.uiServerIndex) + clearToggleButtons() $router.currentRoute.value.name !== 'charging-stations' && $router.push({ name: 'charging-stations' }) }, @@ -51,8 +52,15 @@ - - + + {{ state.simulatorState?.started === true ? 'Stop' : 'Start' }} Simulator + ({ + renderSimulator: randomUUID(), + renderAddChargingStations: randomUUID(), + renderChargingStations: randomUUID(), + loading: false, + uiServerIndex: getFromLocalStorage('uiServerConfigurationIndex', 0) +}) + const app = getCurrentInstance() const clearToggleButtons = (): void => { @@ -126,14 +148,30 @@ const clearToggleButtons = (): void => { } const clearChargingStations = (): void => { - clearToggleButtons() app!.appContext.config.globalProperties.$chargingStations = [] - state.value.renderAddChargingStations = randomUUID() state.value.renderChargingStations = randomUUID() } +const uiClient = app?.appContext.config.globalProperties.$uiClient + +const getSimulatorState = (): void => { + uiClient + .simulatorState() + .then((response: ResponsePayload) => { + state.value.simulatorState = response.state as { started: boolean } + }) + .catch((error: Error) => { + $toast.error('Error at fetching simulator state') + console.error('Error at fetching simulator state:', error) + }) + .finally(() => { + state.value.renderSimulator = randomUUID() + }) +} + const initializeWSEventListeners = () => { app?.appContext.config.globalProperties.$uiClient.registerWSEventListener('open', () => { + getSimulatorState() uiClient .listTemplates() .then((response: ResponsePayload) => { @@ -148,8 +186,10 @@ const initializeWSEventListeners = () => { $toast.error('Error at fetching charging station templates') console.error('Error at fetching charging station templates:', error) }) + .finally(() => { + state.value.renderAddChargingStations = randomUUID() + }) loadChargingStations(() => { - state.value.renderAddChargingStations = randomUUID() state.value.renderChargingStations = randomUUID() }) }) @@ -167,14 +207,6 @@ onMounted(() => { initializeWSEventListeners() }) -const state = ref({ - renderAddChargingStations: randomUUID(), - renderChargingStations: randomUUID(), - loading: false, - uiServerIndex: getFromLocalStorage('uiServerConfigurationIndex', 0) -}) - -const uiClient = app?.appContext.config.globalProperties.$uiClient const uiServerConfigurations: { configuration: UIServerConfigurationSection; index: number }[] = app?.appContext.config.globalProperties.$configuration.uiServer.map( (configuration: UIServerConfigurationSection, index: number) => ({ @@ -221,6 +253,9 @@ const startSimulator = (): void => { $toast.error('Error at starting simulator') console.error('Error at starting simulator:', error) }) + .finally(() => { + getSimulatorState() + }) } const stopSimulator = (): void => { uiClient @@ -235,6 +270,9 @@ const stopSimulator = (): void => { $toast.error('Error at stopping simulator') console.error('Error at stopping simulator:', error) }) + .finally(() => { + getSimulatorState() + }) } @@ -280,7 +318,7 @@ const stopSimulator = (): void => { } #reload-button:active { - background-color: red; + background-color: seagreen; } #action { -- 2.34.1