Skip to content

Commit

Permalink
Feature/382 input editor (#388)
Browse files Browse the repository at this point in the history
* add simple editor (#382)

* add downloading (#382)

* rename

* add editor panel (#382)

* remove caching of charts

* deepsource
  • Loading branch information
ostatni5 authored Feb 24, 2022
1 parent bde3b31 commit e785aef
Show file tree
Hide file tree
Showing 16 changed files with 15,710 additions and 10,453 deletions.
25,735 changes: 15,378 additions & 10,357 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@types/react-dom": "^17.0.11",
"@types/signals": "^1.0.1",
"@types/throttle-debounce": "^2.1.0",
"@uiw/react-textarea-code-editor": "^1.4.16",
"comlink": "^4.3.1",
"ky": "^0.28.7",
"react": "^17.0.2",
Expand Down
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import useMediaQuery from '@mui/material/useMediaQuery';
import * as React from 'react';
import { JsRootService } from './JsRoot/JsRootService';
import { Auth } from './services/AuthService';
import { ShSimulation } from './services/ShSimulationService';
import { ShSimulation } from './services/ShSimulatorService';
import { Store } from './services/StoreService';
import WrapperApp from './WrapperApp/WrapperApp';

Expand Down
8 changes: 4 additions & 4 deletions src/JsRoot/JsRootGraph2D.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Page2D } from './GraphData';

export function JsRootGraph2D(props: Page2D) {
const { JSROOT } = useJSROOT();
// Custom react hook, visible contains the percentage of the containterEl
// Custom react hook, visible contains the percentage of the containterEl
// that is currently visible on screen
const [containerEl, visible] = useVisible<HTMLDivElement>();

Expand All @@ -15,13 +15,13 @@ export function JsRootGraph2D(props: Page2D) {
const [isVisible, setIsVisible] = useState(false);

useEffect(() => {
// Update isVisible if more than 30% of containerEl is visible
// Update isVisible if more than 30% of containerEl is visible
setIsVisible(visible > 0.3);
return () => setIsVisible(false);
}, [visible]);

useEffect(() => {
if (drawn || !visible) return;
if (!visible) return;
const x = props.first_axis.values;
const y = props.second_axis.values;
const z = props.data.values;
Expand Down Expand Up @@ -49,7 +49,7 @@ export function JsRootGraph2D(props: Page2D) {

setObj(histogram);
setDrawn(false);
}, [JSROOT, props, drawn, visible]);
}, [JSROOT, props, visible]);

useEffect(() => {
if (obj && !drawn && isVisible) {
Expand Down
8 changes: 4 additions & 4 deletions src/ThreeEditor/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,9 @@ button[disabled] {
cursor: default;
}

button:hover:not([disabled]) {
/* button:hover:not([disabled]) {
background-color: #fff;
}
} */

button.selected {
background-color: #fff;
Expand Down Expand Up @@ -602,10 +602,10 @@ select:hover {
cursor: default;
}

button:hover:not([disabled]) {
/* button:hover:not([disabled]) {
color: #ccc;
background-color: #444;
}
} */

button.selected {
color: #fff;
Expand Down
14 changes: 1 addition & 13 deletions src/ThreeEditor/js/menubar/Menubar.File.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { UIHorizontalRule, UIPanel } from '../libs/ui.js';
import { createOption } from './Menubar.js';
import { saveString } from '../../../util/File';

function MenubarFile(editor) {
const container = new UIPanel();
Expand Down Expand Up @@ -45,19 +46,6 @@ function MenubarFile(editor) {
);

// Save Editor to file
const link = document.createElement('a');
function save(blob, filename) {
if (link.href) {
URL.revokeObjectURL(link.href);
}

link.href = URL.createObjectURL(blob);
link.download = filename || 'data.json';
link.dispatchEvent(new MouseEvent('click'));
}
function saveString(text, filename) {
save(new Blob([text], { type: 'text/plain' }), filename);
}

options.add(
createOption('option', 'Save', () => {
Expand Down
45 changes: 28 additions & 17 deletions src/WrapperApp/WrapperApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,26 @@ import { DEMO_MODE } from '../util/Config';
import { TabPanel } from './components/TabPanel';
import ResultsPanel from './components/ResultsPanel';
import { useAuth } from '../services/AuthService';
import InputEditorPanel from './components/InputEditor/InputEditorPanel';
import { AboutPanel } from './components/AboutPanel';

function WrapperApp() {
const { editorRef, resultsSimulationData } = useStore();
const { isAuthorized, logout } = useAuth();

const [tabsValue, setTabsValue] = useState(0);
const [tabsValue, setTabsValue] = useState('Editor');

const handleChange = (event: SyntheticEvent, newValue: number) => {
const handleChange = (event: SyntheticEvent, newValue: string) => {
setTabsValue(newValue);
};

useEffect(() => {
if (!isAuthorized) setTabsValue(5);
else setTabsValue(0);
if (!isAuthorized) setTabsValue('Login');
else setTabsValue('Editor');
}, [isAuthorized]);

useEffect(() => {
if (resultsSimulationData) setTabsValue(2);
if (resultsSimulationData) setTabsValue('Results');
}, [resultsSimulationData]);

return (
Expand All @@ -41,44 +42,54 @@ function WrapperApp() {
}}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={tabsValue} onChange={handleChange}>
<Tab label='Editor' />
<Tab label='Run' disabled={DEMO_MODE || !isAuthorized} />
<Tab label='Editor' value={'Editor'} />
<Tab label='Run' value={'Run'} disabled={DEMO_MODE || !isAuthorized} />
<Tab
label='Input Editor'
value={'Input Editor'}
disabled={DEMO_MODE || !isAuthorized}
/>
<Tab
label='Results'
value={'Results'}
disabled={DEMO_MODE || !isAuthorized || !resultsSimulationData}
/>
<Tab label='Projects' disabled />
<Tab label='About' />
<Tab label='Projects' value={'Projects'} disabled />
<Tab label='About' value={'About'} />
<Tab
sx={{ marginLeft: 'auto' }}
label={isAuthorized && !DEMO_MODE ? 'Logout' : 'Login'}
value={'Login'}
onClick={() => isAuthorized && logout()}
disabled={DEMO_MODE}
/>
</Tabs>
</Box>
<TabPanel value={tabsValue} index={0} persistent>
<TabPanel value={tabsValue} index={'Editor'} persistent>
<ThreeEditor
onEditorInitialized={editor => (editorRef.current = editor)}
focus={tabsValue === 0}
focus={tabsValue === 'Editor'}
/>
</TabPanel>
{DEMO_MODE || (
<>
<TabPanel value={tabsValue} index={1}>
<SimulationPanel goToResults={() => setTabsValue(2)} />
<TabPanel value={tabsValue} index={'Run'}>
<SimulationPanel goToResults={() => setTabsValue('Results')} />
</TabPanel>
<TabPanel value={tabsValue} index={'Input Editor'} persistent>
<InputEditorPanel goToRun={() => setTabsValue('Run')} />
</TabPanel>

<TabPanel value={tabsValue} index={2} persistentIfVisited>
<TabPanel value={tabsValue} index={'Results'} persistent>
<ResultsPanel />
</TabPanel>
</>
)}
)}

<TabPanel value={tabsValue} index={4} persistentIfVisited>
<TabPanel value={tabsValue} index={'About'} persistentIfVisited>
<AboutPanel />
</TabPanel>
<TabPanel value={tabsValue} index={5}>
<TabPanel value={tabsValue} index={'Login'}>
<LoginPanel />
</TabPanel>
</Box>
Expand Down
64 changes: 64 additions & 0 deletions src/WrapperApp/components/InputEditor/InputEditorPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Box, Button } from '@mui/material';
import { useState } from 'react';
import { InputFiles, useShSimulation } from '../../../services/ShSimulatorService';
import { useStore } from '../../../services/StoreService';
import { InputFilesEditor } from './InputFilesEditor';

interface InputEditorPanelProps {
goToRun?: () => void;
}

export default function InputEditorPanel(props: InputEditorPanelProps) {
const { editorRef } = useStore();
const { convertToInputFiles, sendRun } = useShSimulation();

const [isInProgress, setInProgress] = useState(false);
const [inputFiles, setInputFiles] = useState<InputFiles>();

const [controller] = useState(new AbortController());

const onClickGenerate = () => {
setInProgress(true);
convertToInputFiles(editorRef.current?.toJSON(), controller.signal)
.then(res => {
setInputFiles({ ...res.content.input_files });
})
.catch()
.finally(() => {
setInProgress(false);
});
};

const runSimulation = (inputFiles: InputFiles) => {
setInProgress(true);
const input = { inputFiles };
sendRun(input, controller.signal)
.then()
.catch()
.finally(() => {
setInProgress(false);
props.goToRun?.call(null);
});
};
return (
<Box
sx={{
margin: '0 auto',
width: '100%',
padding: '3rem',
gap: '1.5rem',
height: 'min-content'
}}>
<Button
variant='contained'
onClick={onClickGenerate}
disabled={isInProgress}
sx={{
marginBottom: '2rem'
}}>
Generate from Editor
</Button>
<InputFilesEditor inputFiles={inputFiles} runSimulation={runSimulation} />
</Box>
);
}
93 changes: 93 additions & 0 deletions src/WrapperApp/components/InputEditor/InputFilesEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { Box, Button, Card, CardActions, CardContent } from '@mui/material';
import React, { useState, useEffect } from 'react';
import { InputFiles } from '../../../services/ShSimulatorService';
import CodeEditor from '@uiw/react-textarea-code-editor';
import { saveString } from '../../../util/File';

interface InputFilesEditorProps {
inputFiles?: InputFiles;
runSimulation?: (inputFiles: InputFiles) => void;
saveAndExit?: (inputFiles: InputFiles) => void;
closeEditor?: () => void;
innerState?: boolean;
}

const _emptyInputFiles: InputFiles = {
'geo.dat': '',
'beam.dat': '',
'detect.dat': '',
'mat.dat': ''
};
export function InputFilesEditor(props: InputFilesEditorProps) {
const [inputFiles, setInputFiles] = useState<InputFiles>(
props.inputFiles ?? { ..._emptyInputFiles }
);

useEffect(() => {
if (!props.innerState) setInputFiles({ ...(props.inputFiles ?? _emptyInputFiles) });
}, [props.innerState, props.inputFiles]);


return (
<Card sx={{ minHeight: '100%' }}>
<CardActions sx={{ justifyContent: 'flex-end' }}>
{props.runSimulation && (
<Button
color='success'
variant='contained'
onClick={() => props.runSimulation?.call(null, inputFiles)}>
Run input files
</Button>
)}
<Button
onClick={() =>
Object.entries(inputFiles).map(([name, value]) => saveString(value, name))
}>
Download all
</Button>
{props.saveAndExit && (
<Button onClick={() => props.saveAndExit?.call(null, inputFiles)}>
Save and exit
</Button>
)}
{props.closeEditor && (
<Button onClick={() => props.closeEditor?.call(null)}>Close</Button>
)}
</CardActions>
<CardContent>
{Object.entries(inputFiles).map(([name, value]) => {
return (
<Box key={name}>
<h2>
{name}
<Button
onClick={() => {
saveString(value, name);
}}>
Download
</Button>
</h2>
<CodeEditor
value={value}
language='sql'
placeholder={`Please enter ${name} content.`}
onChange={evn =>
setInputFiles(old => {
return { ...old, [name]: evn.target.value };
})
}
padding={15}
style={{
fontSize: 12,
backgroundColor: '#f5f5f5',
fontFamily:
'ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace'
}}
/>
</Box>
);
})}
</CardContent>
</Card>
);
}
Loading

0 comments on commit e785aef

Please sign in to comment.