Skip to content

Commit

Permalink
feat: scenario editor and visualizer layout (#146)
Browse files Browse the repository at this point in the history
* 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 b17b0a3

* fix in revert
  • Loading branch information
NektariosFifes committed Apr 11, 2023
1 parent 19dc60d commit 5f0f4e1
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 139 deletions.
61 changes: 50 additions & 11 deletions 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: [],
};
5 changes: 2 additions & 3 deletions Desktop/src/renderer/containers/Editor/index.tsx
Expand Up @@ -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 (
<EditorContext.Provider value={{ state: EditorState, dispatch }}>
Expand Down
17 changes: 0 additions & 17 deletions Desktop/src/renderer/containers/Editor/reducers/index.ts

This file was deleted.

32 changes: 32 additions & 0 deletions 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 (
<EditorContext.Provider value={{ state, dispatch }}>
{children}
</EditorContext.Provider>
);
}

export { EditorReducer, EditorStateProvider, EditorContext };
@@ -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 (
<div
style={{
height: '100%',
left: '48px',
width: '50%',
overflow: 'hidden',
}}
>
<>
<AceEditor
mode="java"
theme="github"
onChange={(code) => setContent(code)}
name="UNIQUE_ID_OF_DIV"
editorProps={{ $blockScrolling: true }}
/>
</>
</div>
);
}

export default ScenarioEditor;
@@ -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 <div />;
}
return (
<>
<h2>Scenarios</h2>
{/* eslint-disable-next-line react/prop-types */}
{Object.keys(scenarioObject.scenarios).map((scenarioName) => {
const name = scenarioName.match(new RegExp(/[^-]*$/, 'gm')); //NOSONAR
return (
<div key={scenarioName}>
<div
style={{
fontFamily:
'ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace',
fontSize: '1rem',
lineHeight: '1.5rem',
}}
>
{name[0]}
<div>
{/* eslint-disable-next-line react/button-has-type */}
<button
onClick={() => {
dispatch({
type: ACTIONS_IDS.simulateAction,
payload: {
actionName: scenarioName,
type: ACTIONS_IDS.simpleInvocation,
},
});
updateRegister({
...actionsRegister,
pendingAction: scenarioName,
});
}}
>
Simulate
</button>
</div>
</div>
</div>
);
})}
</>
);
}

// eslint-disable-next-line react/prop-types
function GenerateOperationsView({ operationsObj }) {
console.log(operationsObj);
return <p>Test</p>;
}

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 (
<div
style={{
width: '50%',
height: '100%',
padding: 5,
margin: '0px',
marginLeft: 7,
marginTop: 1,
backgroundColor: 'azure',
}}
>
<GenerateScenariosView scenarioObject={currentScenario} />
</div>
);
}

export default ScenarioVisualizer;
Expand Up @@ -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({
Expand Down

0 comments on commit 5f0f4e1

Please sign in to comment.