Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added editor page #106

Merged
merged 2 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"@fortawesome/react-fontawesome": "^0.1.16",
"@monaco-editor/react": "^4.3.1",
"@mui/material": "^5.2.3",
"@opuscapita/react-filemanager": "^1.1.11",
"@opuscapita/react-filemanager-connector-node-v1": "^1.1.11",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
Expand All @@ -33,6 +35,7 @@
"react-flow-renderer": "^9.7.3",
"react-hook-form": "^7.21.2",
"react-idle-timer": "^4.6.4",
"react-lazylog": "^4.5.3",
"react-lottie": "^1.2.3",
"react-router-dom": "5.2.0",
"react-scripts": "5.0.0",
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ import Settings from './pages/Settings';
import TeamDetail from './pages/TeamDetail';
import TeamGroup from './pages/TeamGroup';
import Teams from './pages/Teams';
import PipelineEditor from './pages/Editor';
import RemoveLogs from './pages/RemoveLogs';
import PipelinesPermission from './pages/PipelinesPermission';
import createCustomTheme from './theme';
import UseCheckTheme from './hooks/useCheckTheme';

export const ColorModeContext = React.createContext({
toggleColorMode: () => {},
Expand Down Expand Up @@ -92,6 +94,7 @@ function App() {
<Box className="app" backgroundColor="background.main">
<UserAuth refreshTokenUrl="/refreshtoken" LogincallbackUrl="/loginCallback" loginUrl="/webapp/login" logoutUrl="/webapp/logout">
<CssBaseline />
<UseCheckTheme />
<Switch>
<Route exact path="/congratulations">
<Congratulations />
Expand All @@ -109,6 +112,10 @@ function App() {
<LogoutUser />
</PrivateRoute>

<PrivateRoute exact path="/editor/:pipelineId">
<PipelineEditor />
</PrivateRoute>

<PrivateRoute
exact
path={[
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/components/DrawerContent/LogsDrawer/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Box } from '@mui/material';
import React from 'react';
import { LazyLog, ScrollFollow } from 'react-lazylog';

const LogsDrawer = ({ url = 'https://gist.githubusercontent.com/shadow-fox/5356157/raw/1b63df47e885d415705d175b7f6b87989f9d4214/mongolog' }) => {
return (
<Box height="100%" width="100%" bgcolor="#000">
<ScrollFollow startFollowing={true} render={({ follow, onScroll }) => <LazyLog url={url} stream follow={follow} onScroll={onScroll} />} />
</Box>
);
};

export default LogsDrawer;
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ const ShowYAMLCodeDrawer = ({ handleClose }) => {
path={file.name}
defaultLanguage={file.language}
defaultValue={file.value}
options={{
automaticLayout: true,
}}
/>
</Box>
</Box>
Expand Down
12 changes: 0 additions & 12 deletions frontend/src/components/ThemeToggle/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,6 @@ const ThemeToggle = (props) => {
const theme = useTheme();
const colorMode = React.useContext(ColorModeContext);

// Retrieve color mode on load
React.useEffect(() => {
const themeData = localStorage.getItem('theme');

if (themeData) {
if (themeData !== theme.palette.mode) {
colorMode.toggleColorMode();
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

// Toggle color mode on click
async function handleClick() {
const color = theme.palette.mode === 'light' ? 'dark' : 'light';
Expand Down
25 changes: 25 additions & 0 deletions frontend/src/hooks/useCheckTheme.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useTheme } from '@mui/material';
import { useEffect } from 'react';
import { useContext } from 'react';
import { ColorModeContext } from '../App';

const CheckTheme = () => {
const theme = useTheme();
const colorMode = useContext(ColorModeContext);

useEffect(() => {
const themeData = localStorage.getItem('theme');

if (themeData) {
if (themeData !== theme.palette.mode) {
colorMode.toggleColorMode();
}
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return null;
};

export default CheckTheme;
216 changes: 216 additions & 0 deletions frontend/src/pages/Editor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { faPlayCircle } from '@fortawesome/free-regular-svg-icons';
import { faCaretDown } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Editor from '@monaco-editor/react';
import { AppBar, Box, Button, Chip, Drawer, FormControl, Grid, InputLabel, MenuItem, Select, Toolbar, Typography, useTheme } from '@mui/material';
import Navbar from '../components/Navbar';
import { FileManager, FileNavigator } from '@opuscapita/react-filemanager';
import connectorNodeV1 from '@opuscapita/react-filemanager-connector-node-v1';
import { useContext, useRef, useState } from 'react';
import LogsDrawer from '../components/DrawerContent/LogsDrawer';
import customDrawerStyles from '../utils/drawerStyles';
import { ColorModeContext } from '../App';

const drawerWidth = 240;
const apiOptions = {
...connectorNodeV1.apiOptions,
apiRoot: `https://demo.core.dev.opuscapita.com/filemanager/master`, // Or you local Server Node V1 installation.
};

const PipelineEditor = () => {
// States
const [isOpenLogs, setIsOpenLogs] = useState(false);
const [selectedFile, setSelectedFile] = useState(FILE_MANAGER_MOCK['1']);
const [locations, setLocations] = useState([]);

// Ref
const editorRef = useRef(null);

// Hooks
const theme = useTheme();
const colorMode = useContext(ColorModeContext);

// Functions
const handleThemeSelect = (e) => {
const color = e.target.value;
localStorage.setItem('theme', color);
colorMode.toggleColorMode();
};

const handleEditorOnMount = (editor) => {
editorRef.current = editor;

window.addEventListener('resize', () => {
editor.layout({
width: 'auto',
height: 'auto',
});
});
};

return (
<Box sx={{ display: 'flex' }}>
<AppBar
elevation={0}
position="fixed"
sx={{ zIndex: (theme) => theme.zIndex.drawer, background: (theme) => theme.palette.background.secondary, borderBottom: 1, borderColor: 'divider' }}>
<Toolbar>
<Navbar />
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
sx={{
width: drawerWidth,
flexShrink: 0,
zIndex: 1100,

[`& .MuiDrawer-paper`]: { width: drawerWidth, boxSizing: 'border-box', backgroundColor: 'editorPageBg.main', border: 'none' },
}}>
<Toolbar />
<Box sx={{ height: '100%', pr: 1, pl: 1 }}>
<Box mt={5.5}>
<FormControl size="small" sx={{ backgroundColor: 'background.main', width: '100%' }}>
<InputLabel id="demo-simple-select-standard-label">Theme</InputLabel>
<Select
IconComponent={() => <Box component={FontAwesomeIcon} icon={faCaretDown} fontSize="1.5rem" mr={1} color="divider" />}
labelId="demo-simple-select-standard-label"
id="demo-simple-select-standard"
value={theme.palette.mode}
onChange={handleThemeSelect}
label="Theme">
<MenuItem value="light">Light</MenuItem>
<MenuItem value="dark">Dark</MenuItem>
</Select>
</FormControl>

<FormControl size="small" sx={{ mt: 2, backgroundColor: 'background.main', width: '100%' }}>
<InputLabel id="demo-simple-select-standard-label">Dev worker</InputLabel>
<Select
IconComponent={() => <Box component={FontAwesomeIcon} icon={faCaretDown} fontSize="1.5rem" mr={1} color="divider" />}
labelId="demo-simple-select-standard-label"
id="demo-simple-select-standard"
value=""
onChange={() => {}}
label="Dev worker"></Select>
</FormControl>

<FormControl size="small" sx={{ mt: 2, backgroundColor: 'background.main', width: '100%' }}>
<InputLabel id="demo-simple-select-standard-label">Draft</InputLabel>
<Select
IconComponent={() => <Box component={FontAwesomeIcon} icon={faCaretDown} fontSize="1.5rem" mr={1} color="divider" />}
labelId="demo-simple-select-standard-label"
id="demo-simple-select-standard"
value=""
onChange={() => {}}
label="Draft"></Select>
</FormControl>

<Box sx={{ height: '332px', backgroundColor: 'background.main', border: '1px solid #D3D3D3', mt: '28px', borderRadius: '7px' }}>
<FileManager>
<FileNavigator
id="filemanager-1"
api={connectorNodeV1.api}
apiOptions={apiOptions}
capabilities={connectorNodeV1.capabilities}
listViewLayout={connectorNodeV1.listViewLayout}
viewLayoutOptions={connectorNodeV1.viewLayoutOptions}
onResourceLocationChange={(resourceLocation) => setLocations(resourceLocation)}
onResourceItemDoubleClick={({ event, number, rowData }) => console.log(rowData)}
onResourceItemClick={({ event, number, rowData }) => setSelectedFile({ rowData, ...FILE_MANAGER_MOCK[rowData.id] })}
/>
</FileManager>
</Box>
</Box>
</Box>
</Drawer>
<Box component="main" sx={{ flexGrow: 1, p: 4, height: '100vh' }} backgroundColor="editorPageBg.main">
<Toolbar />
<Box width="100%">
<Grid pt={1} container alignItems="center" justifyContent="space-between">
<Grid item>
<Typography component="h2" variant="h4" fontWeight={700} color="text.primary">
Pipeline permissions {'>'} Remove Logs {'>'} Clear the logs
</Typography>
<Typography variant="h4" mt={0.4}>
/{locations.map((loc, idx) => `${idx !== 0 ? '/' : ''}${loc.name}`)} /{selectedFile && selectedFile.name}
</Typography>
</Grid>

<Grid item sx={{ mt: { xxs: 2, lg: 0 } }}>
<Button variant="contained">Save</Button>
<Button variant="outlined" sx={{ mr: 1.4, ml: 1.4, backgroundColor: 'background.main' }}>
Save draft
</Button>
<Button variant="outlined" sx={{ backgroundColor: 'background.main' }}>
Close
</Button>
</Grid>
</Grid>

<Grid container mt={3} alignItems="center">
<Chip
avatar={<Box component={FontAwesomeIcon} sx={{ color: '#ffffff!important', fontSize: 18 }} icon={faPlayCircle} />}
label="Play"
sx={{ mr: 0, bgcolor: 'primary.main', color: '#fff', fontWeight: 600 }}
/>
<Button variant="text" sx={{ ml: 2, color: 'cyan.main' }} onClick={() => setIsOpenLogs(true)}>
Logs
</Button>
</Grid>
</Box>

<Box mt={4}>
<Editor
onMount={handleEditorOnMount}
language={selectedFile.language}
path={selectedFile.name}
defaultValue={selectedFile.content}
value={selectedFile.content}
theme={theme.palette.mode === 'dark' ? 'vs-dark' : 'customTheme'}
height="357px"
/>
</Box>
</Box>

<Drawer anchor="right" open={isOpenLogs} onClose={() => setIsOpenLogs(!isOpenLogs)} sx={customDrawerStyles}>
<LogsDrawer />
</Drawer>
</Box>
);
};

const PYTHON_CODE_EXAMPLE = `import banana


class Monkey:
# Bananas the monkey can eat
capacity = 10
def eat(self, n):
"""Make the monkey eat n bananas!"""
self.capacity -= n * banana.size

def feeding_frenzy(self):
self.eat(9.25)
return "Yum yum"

`;

const FILE_MANAGER_MOCK = {
1: {
language: 'python',
name: 'monkey.py',
content: PYTHON_CODE_EXAMPLE,
},
L2hlbGxvLXdvcmxkLmpz: {
language: 'javascript',
name: 'hello_world.js',
content: `
const message = 'Hello world';

console.log(message)
`,
},
};

export default PipelineEditor;
9 changes: 9 additions & 0 deletions frontend/src/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ const createCustomTheme = (mode) => ({
pipelineOnline: '#72B842',
pipelineOnlineText: '#2E6707',
},
editorPageBg: {
main: '#F4F6F9',
},
}
: {
success: {
Expand Down Expand Up @@ -96,6 +99,9 @@ const createCustomTheme = (mode) => ({
pipelineOnline: '#72B842',
pipelineOnlineText: '#72B842',
},
editorPageBg: {
main: 'rgba(14, 25, 40, 1)',
},
}),
},
breakpoints: {
Expand Down Expand Up @@ -125,6 +131,9 @@ const createCustomTheme = (mode) => ({
fontWeight: 900,
fontSize: '1.0625rem',
},
h4: {
fontSize: '1.25rem',
},
subtitle1: {
fontSize: '.75rem',
},
Expand Down