From 5f0f4e16972739d4d5e9745fc110719f27b71812 Mon Sep 17 00:00:00 2001 From: NektariosFifes <61620751+NektariosFifes@users.noreply.github.com> Date: Tue, 11 Apr 2023 12:26:26 +0300 Subject: [PATCH] feat: scenario editor and visualizer layout (#146) * added question for choosing server in cli * Added Icons Added project details * restructuring in desktop application code * re-organized code for simplicity and added cli and desktopApplication interfaces that will be used to access the simulator functionality by the cli and desktopApp respectively * temp commit * Revert "restructuring in desktop application code" This reverts commit b17b0a3a * fix in revert --- .../containers/Editor/constants/index.ts | 61 +++++++-- .../src/renderer/containers/Editor/index.tsx | 5 +- .../containers/Editor/reducers/index.ts | 17 --- .../containers/Editor/reducers/index.tsx | 32 +++++ .../Workbench/components/ScenarioEditor.tsx | 78 +++++++++++ .../components/ScenarioVisualizer.tsx | 128 ++++++++++++++++++ .../Workbench/components/SideBar.tsx | 2 + .../containers/Workbench/constants/index.ts | 56 -------- .../renderer/containers/Workbench/index.tsx | 4 + .../containers/Workbench/reducers/index.tsx | 52 ------- 10 files changed, 296 insertions(+), 139 deletions(-) delete mode 100644 Desktop/src/renderer/containers/Editor/reducers/index.ts create mode 100644 Desktop/src/renderer/containers/Editor/reducers/index.tsx create mode 100644 Desktop/src/renderer/containers/Workbench/components/ScenarioEditor.tsx create mode 100644 Desktop/src/renderer/containers/Workbench/components/ScenarioVisualizer.tsx delete mode 100644 Desktop/src/renderer/containers/Workbench/constants/index.ts delete mode 100644 Desktop/src/renderer/containers/Workbench/reducers/index.tsx diff --git a/Desktop/src/renderer/containers/Editor/constants/index.ts b/Desktop/src/renderer/containers/Editor/constants/index.ts index 39ef11c1d..53adbf0e9 100644 --- a/Desktop/src/renderer/containers/Editor/constants/index.ts +++ b/Desktop/src/renderer/containers/Editor/constants/index.ts @@ -1,16 +1,55 @@ -// @ts-ignore -import * as types from '../types'; +import * as types from '../../Workbench/types'; export const ACTIONS_IDS = { - set_fp_AsyncApi: 0, - set_fp_Scenario: 1, - check_fp_AsynApi_Validity: 2, - check_fp_Scenario_Validity: 3, - check_format_AsyncApi_Validity: 4, - check_format_Scenario_Validity: 5, + checkScenarioSyntax: 0, + executeOperation: 2, + executeScenario: 3, + cancelExecution: 4, + setCurrentScenarioFile: 5, + scenarioUpdated: 6, }; -export const defaultEditorState: types.DefaultEditorStateType = { - asyncApiFilepath: './API.yaml', - scenarioFilepath: './scenario.yaml', +const defaultScenario = `version: "0.0.1" +user-logs-on: + game/server/{serverId}/events/player/{playerId}/connect: + playerId : + min: 0 + max: 2000 + serverId: + min: 0 + max: 4 +user-gameLoop: + loop: + interval: + 600 + cycles: + 5 + game/server/{serverId}/events/player/{playerId}/hit: + serverId: '1' + playerId: + regex: '^[\\w\\d]{1,22}$' + + game/server/{serverId}/events/player/{playerId}/item/{itemId}/pickup: + serverId: '1' + playerId: + regex: '^[\\w\\d]{1,22}$' + itemId: + min: 0 + max: 4 + + game/server/{serverId}/events/player/{playerId}/chat: + serverId: '1' + playerId: + regex: '^[\\w\\d]{1,22}$' + payload: 'well played m8' + +scenario-SimpleGame: + - user-logs-on + - user-gameLoop`; + +export const defaultEditorState: types.DefaultWorkBenchStateType = { + currentScenario: defaultScenario, + scenarioUpdated: false, + pendingRequestExecutions: {}, + applicationActionsHistory: [], }; diff --git a/Desktop/src/renderer/containers/Editor/index.tsx b/Desktop/src/renderer/containers/Editor/index.tsx index 3e80974b9..f403cfc06 100644 --- a/Desktop/src/renderer/containers/Editor/index.tsx +++ b/Desktop/src/renderer/containers/Editor/index.tsx @@ -2,16 +2,15 @@ // @ts-nocheck import React, { useReducer } from 'react'; import { EditorPropsType } from './types'; -import { editorReducer } from './reducers'; +import { EditorReducer, EditorContext } from './reducers'; import { defaultEditorState } from './constants'; import { TitleBar } from '../TitleBar'; import template from '../TitleBar/menuTemplate'; import ScenarioWorkbench from '../Workbench'; import icon from '../../../../assets/icon.svg'; -import { EditorContext } from '../Workbench/reducers'; function Editor(props: EditorPropsType): JSX.Element { - const [EditorState, dispatch] = useReducer(editorReducer, defaultEditorState); + const [EditorState, dispatch] = useReducer(EditorReducer, defaultEditorState); return ( diff --git a/Desktop/src/renderer/containers/Editor/reducers/index.ts b/Desktop/src/renderer/containers/Editor/reducers/index.ts deleted file mode 100644 index 483bbbe1c..000000000 --- a/Desktop/src/renderer/containers/Editor/reducers/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ACTIONS_IDS } from '../constants'; -// eslint-disable-next-line import/prefer-default-export -export const editorReducer = (state: any, action: any) => { - switch (action.type) { - case ACTIONS_IDS.set_fp_AsyncApi: - return [...state, { asyncApiFilepath: action.payload.filepath }]; - case ACTIONS_IDS.set_fp_Scenario: - return [ - ...state, - { - scenarioFilepath: action.payload.filepath, - }, - ]; - default: - return state; - } -}; diff --git a/Desktop/src/renderer/containers/Editor/reducers/index.tsx b/Desktop/src/renderer/containers/Editor/reducers/index.tsx new file mode 100644 index 000000000..02237d8e7 --- /dev/null +++ b/Desktop/src/renderer/containers/Editor/reducers/index.tsx @@ -0,0 +1,32 @@ +import React, { useReducer } from 'react'; +import { ACTIONS_IDS, defaultEditorState } from '../constants'; +// eslint-disable-next-line import/prefer-default-export +const EditorReducer = (state: any, action: any) => { + switch (action.type) { + case ACTIONS_IDS.checkScenarioSyntax: + return { ...state }; + case ACTIONS_IDS.scenarioUpdated: + return { ...state, scenarioUpdated: true }; + case ACTIONS_IDS.executeScenario: + return { ...state }; + case ACTIONS_IDS.executeOperation: + return { ...state }; + case ACTIONS_IDS.cancelExecution: + return { ...state }; + default: + return state; + } +}; + +const EditorContext = React.createContext(defaultEditorState); + +function EditorStateProvider({ children }) { + const [state, dispatch] = useReducer(EditorReducer, defaultEditorState); + return ( + + {children} + + ); +} + +export { EditorReducer, EditorStateProvider, EditorContext }; diff --git a/Desktop/src/renderer/containers/Workbench/components/ScenarioEditor.tsx b/Desktop/src/renderer/containers/Workbench/components/ScenarioEditor.tsx new file mode 100644 index 000000000..88d99ffd5 --- /dev/null +++ b/Desktop/src/renderer/containers/Workbench/components/ScenarioEditor.tsx @@ -0,0 +1,78 @@ +import React, { useCallback, useContext, useEffect, useState } from 'react'; +import AceEditor from 'react-ace'; + +import 'ace-builds/src-noconflict/mode-java'; +import 'ace-builds/src-noconflict/theme-github'; +import { ipcRenderer } from 'electron'; +import { ACTIONS_IDS } from '../../Editor/constants'; + +// Example style, you can use another +function ScenarioEditor({ EditorState, dispatch }): JSX.Element { + const [EditorContent, setContent] = useState('myScenario:'); + + const getContent = useCallback(() => { + return EditorContent; + }, [EditorContent]); + + const setUpForVisualization = useCallback( + (value) => { + EditorState.visualizationRequested = value; + }, + [EditorState] + ); + + useEffect(() => { + function getCurrentScenario() { + return getContent(); + } + function updateVisualizationObj(_event: any, obj: any) { + dispatch({ + type: ACTIONS_IDS.setCurrentScenarioFile, + payload: obj, + }); + } + console.log('effectara'); + if (EditorState.visualizationRequested === true) { + ipcRenderer.on('editor/visualizationReady', updateVisualizationObj); + ipcRenderer.send('editor/visualizeRequest', getCurrentScenario()); + setUpForVisualization(false); + } + + // TODO add case for save scenario action + + return function onUnmount() { + ipcRenderer.removeListener( + 'editor/visualizationReady', + updateVisualizationObj + ); + }; + }, [ + setUpForVisualization, + getContent, + EditorState.visualizationRequested, + EditorState, + dispatch, + ]); + return ( +
+ <> + setContent(code)} + name="UNIQUE_ID_OF_DIV" + editorProps={{ $blockScrolling: true }} + /> + +
+ ); +} + +export default ScenarioEditor; diff --git a/Desktop/src/renderer/containers/Workbench/components/ScenarioVisualizer.tsx b/Desktop/src/renderer/containers/Workbench/components/ScenarioVisualizer.tsx new file mode 100644 index 000000000..dbbac3aed --- /dev/null +++ b/Desktop/src/renderer/containers/Workbench/components/ScenarioVisualizer.tsx @@ -0,0 +1,128 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +import React, { useContext, useEffect, useState } from 'react'; +import { ipcRenderer } from 'electron'; +// eslint-disable-next-line import/no-cycle,import/no-duplicates +// eslint-disable-next-line import/no-cycle +import { WorkBenchContext } from '..'; +import { ACTIONS_IDS } from '../../Editor/constants'; + +function ScenarioVisualizer({ EditorState, dispatch }): JSX.Element { + const [actionsRegister, updateRegister] = useState({ + pendingAction: null, + doneActions: {}, + }); + + // eslint-disable-next-line react/prop-types + function GenerateScenariosView({ scenarioObject }) { + // eslint-disable-next-line react/prop-types + if (!scenarioObject.scenarios) { + return
; + } + return ( + <> +

Scenarios

+ {/* eslint-disable-next-line react/prop-types */} + {Object.keys(scenarioObject.scenarios).map((scenarioName) => { + const name = scenarioName.match(new RegExp(/[^-]*$/, 'gm')); //NOSONAR + return ( +
+
+ {name[0]} +
+ {/* eslint-disable-next-line react/button-has-type */} + +
+
+
+ ); + })} + + ); + } + + // eslint-disable-next-line react/prop-types + function GenerateOperationsView({ operationsObj }) { + console.log(operationsObj); + return

Test

; + } + + const [currentScenario, setScenario] = useState({}); + + // eslint-disable-next-line @typescript-eslint/no-redeclare + function setLocalState(scenario) { + console.log(scenario); + setScenario(scenario); + } + + useEffect(() => { + console.log('visualizer'); + + if (actionsRegister.pendingAction) { + ipcRenderer + .invoke('editor/action', actionsRegister.pendingAction) + .then((r) => + dispatch({ + type: ACTIONS_IDS.visualizationChangeStatus, + }) + ) + .catch((err) => {}); + } + if (EditorState.scenarioUpdated === true) { + console.log('GENERATING'); + setLocalState(EditorState.currentValidScenario); + dispatch({ + type: ACTIONS_IDS.visualizationChangeStatus, + }); + + // dispatch({ type: ACTIONS_IDS.visualizationGenerating }); + } + + // TODO add case for save scenario action + + return function onUnmount() { + // dispatch({ type: ACTIONS_IDS.visualizationGenerating }); + }; + }, [EditorState, actionsRegister]); + + return ( +
+ +
+ ); +} + +export default ScenarioVisualizer; diff --git a/Desktop/src/renderer/containers/Workbench/components/SideBar.tsx b/Desktop/src/renderer/containers/Workbench/components/SideBar.tsx index 36390596e..fd1e5083f 100644 --- a/Desktop/src/renderer/containers/Workbench/components/SideBar.tsx +++ b/Desktop/src/renderer/containers/Workbench/components/SideBar.tsx @@ -3,10 +3,12 @@ import React, { useState } from 'react'; import { VscRunAll } from 'react-icons/vsc'; import { IconContext } from 'react-icons'; +import {ACTIONS_IDS} from "../../Editor/constants"; function SideBar({ EditorState, dispatch }): JSX.Element { async function VisualizeScenario() { console.log(dispatch); + dispatch({ type: ACTIONS_IDS.checkScenarioSyntax }); } const [RunIconStyle, SetRunStyle] = useState({ diff --git a/Desktop/src/renderer/containers/Workbench/constants/index.ts b/Desktop/src/renderer/containers/Workbench/constants/index.ts deleted file mode 100644 index 54dde7749..000000000 --- a/Desktop/src/renderer/containers/Workbench/constants/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as types from '../types'; - -export const ACTIONS_IDS = { - checkScenarioSyntax: 0, - visualizeScenarioFile: 1, - executeOperation: 2, - executeScenario: 3, - cancelExecution: 4, - setCurrentScenarioFile: 5, - scenarioUpdated: 6, -}; - -export const defaultEditorState: types.DefaultWorkBenchStateType = { - currentScenario: {}, - scenarioUpdated: false, - pendingRequestExecutions: {}, - applicationActionsHistory: [], -}; - -export const defaultScenario = `version: "0.0.1" -user-logs-on: - game/server/{serverId}/events/player/{playerId}/connect: - playerId : - min: 0 - max: 2000 - serverId: - min: 0 - max: 4 -user-gameLoop: - loop: - interval: - 600 - cycles: - 5 - game/server/{serverId}/events/player/{playerId}/hit: - serverId: '1' - playerId: - regex: '^[\\w\\d]{1,22}$' - - game/server/{serverId}/events/player/{playerId}/item/{itemId}/pickup: - serverId: '1' - playerId: - regex: '^[\\w\\d]{1,22}$' - itemId: - min: 0 - max: 4 - - game/server/{serverId}/events/player/{playerId}/chat: - serverId: '1' - playerId: - regex: '^[\\w\\d]{1,22}$' - payload: 'well played m8' - -scenario-SimpleGame: - - user-logs-on - - user-gameLoop`; diff --git a/Desktop/src/renderer/containers/Workbench/index.tsx b/Desktop/src/renderer/containers/Workbench/index.tsx index 86492d9d4..dbba16e2d 100644 --- a/Desktop/src/renderer/containers/Workbench/index.tsx +++ b/Desktop/src/renderer/containers/Workbench/index.tsx @@ -1,12 +1,16 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import React from 'react'; +import ScenarioEditor from './components/ScenarioEditor'; +import ScenarioVisualizer from './components/ScenarioVisualizer'; import SideBar from './components/SideBar'; function ScenarioWorkbench({ EditorState, dispatch }): JSX.Element { return ( <> + + ); } diff --git a/Desktop/src/renderer/containers/Workbench/reducers/index.tsx b/Desktop/src/renderer/containers/Workbench/reducers/index.tsx deleted file mode 100644 index bdf7fd444..000000000 --- a/Desktop/src/renderer/containers/Workbench/reducers/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useReducer } from 'react'; -import { ACTIONS_IDS, defaultEditorState } from '../constants'; -// eslint-disable-next-line import/prefer-default-export -const EditorReducer = (state: any, action: any) => { - switch (action.type) { - case ACTIONS_IDS.visualizeScenarioFile: - console.log('test'); - console.log(state.pendingActions); - return { - ...state, - pendingActions: [ - ...state.pendingActions, - { [action.payload.actionName]: action.payload.type }, - ], - }; - - case ACTIONS_IDS.setCurrentScenarioFile: - console.log('setScenarioFile'); - console.log(action); - return { - ...state, - currentValidScenario: action.payload, - scenarioUpdated: true, - }; - case ACTIONS_IDS.executeOperartion: - return { - ...state, - - scenarioFilepath: action.payload.operation, - }; - case ACTIONS_IDS.visualizationChangeStatus: - return { - ...state, - scenarioUpdated: false, - }; - default: - return state; - } -}; - -const EditorContext = React.createContext(defaultEditorState); - -function EditorStateProvider({ children }) { - const [state, dispatch] = useReducer(EditorReducer, defaultEditorState); - return ( - - {children} - - ); -} - -export { EditorStateProvider, EditorContext };