🔨 Making Graph Visualization Green + Fixing Editor UI (#2833)

Signed-off-by: Sayan Mondal <sayan@chaosnative.com>
This commit is contained in:
Sayan Mondal 2021-05-24 15:49:48 +05:30 committed by GitHub
parent 0c49869d10
commit 6563d0f435
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 138 additions and 163 deletions

View File

@ -13,7 +13,11 @@ import SelectAllTwoToneIcon from '@material-ui/icons/SelectAllTwoTone';
import UndoTwoToneIcon from '@material-ui/icons/UndoTwoTone';
import UnfoldLessTwoToneIcon from '@material-ui/icons/UnfoldLessTwoTone';
import UnfoldMoreTwoToneIcon from '@material-ui/icons/UnfoldMoreTwoTone';
import React, { useEffect, useState } from 'react';
import AceEditor from 'react-ace';
import { useTranslation } from 'react-i18next';
import useStyles from './styles';
import { AceValidations, parseYamlValidations } from './Validations';
import 'ace-builds/src-min-noconflict/ext-beautify';
import 'ace-builds/src-min-noconflict/ext-code_lens';
import 'ace-builds/src-min-noconflict/ext-elastic_tabstops_lite';
@ -36,10 +40,6 @@ import 'ace-builds/src-min-noconflict/ext-themelist';
import 'ace-builds/src-min-noconflict/ext-whitespace';
import 'brace/mode/yaml';
import 'brace/theme/cobalt';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import useStyles from './styles';
import { AceValidations, parseYamlValidations } from './Validations';
interface YamlEditorProps {
content: string;
@ -47,6 +47,7 @@ interface YamlEditorProps {
readOnly: boolean;
setButtonState?: (btnState: boolean) => void;
saveWorkflowChange?: (updatedManifest: string) => void;
className?: Object;
}
const YamlEditor: React.FC<YamlEditorProps> = ({
@ -55,6 +56,7 @@ const YamlEditor: React.FC<YamlEditorProps> = ({
readOnly,
setButtonState,
saveWorkflowChange,
className,
}) => {
const classes = useStyles();
const { palette } = useTheme();
@ -232,7 +234,7 @@ const YamlEditor: React.FC<YamlEditorProps> = ({
return (
<div
className={classes.editorBackgroundFull}
className={`${classes.editorBackgroundFull} ${className}`}
id="editor"
data-cy="WorkflowEditor"
>
@ -439,121 +441,111 @@ const YamlEditor: React.FC<YamlEditorProps> = ({
</div>
)}
</div>
<div className={classes.fullWidth}>
<Box display="flex" p={1} className={classes.editorContainer}>
<Box
p={1}
flexGrow={1}
className={classes.editorGrid}
id="resize-editor"
<div className={classes.editor}>
<AceEditor
mode="yaml"
theme="cobalt"
name="code"
width="100%"
height="100%"
maxLines={12000}
minLines={1}
highlightActiveLine={false}
readOnly={readOnly}
tabSize={2}
wrapEnabled
ref={YamlAce}
showGutter
onChange={onEditorChange}
showPrintMargin={false}
enableBasicAutocompletion
enableSnippets
enableLiveAutocompletion
value={editorState.content}
editorProps={{
$blockScrolling: Infinity,
$useWorker: true,
}}
onLoad={(editor) => {
editor.setReadOnly(readOnly);
editor.setOptions({
fontFamily: 'monospace',
highlightGutterLine: false,
autoScrollEditorIntoView: true,
tooltipFollowsMouse: true,
displayIndentGuides: false,
});
editor.focus();
editor.setHighlightSelectedWord(true);
editor.session.setFoldStyle('markbeginend');
editor.setShowFoldWidgets(true);
editor.setAnimatedScroll(true);
editor.setShowInvisibles(false);
editor.setFontSize('0.98rem');
editor.container.style.background = palette.common.black;
editor.container.style.lineHeight = '160%';
const nodeStyle = (document.getElementsByClassName(
'ace_gutter'
)[0] as any).style;
nodeStyle.color = palette.secondary.contrastText;
nodeStyle.borderRight = 0;
nodeStyle.background = palette.common.black;
}}
onCursorChange={(selection) => {
(YamlAce.current!.editor as any).setOptions({
autoScrollEditorIntoView: true,
tooltipFollowsMouse: true,
});
const nodeStyleActiveList = document.getElementsByClassName(
'ace_gutter-cell'
);
for (let i = 0; i < nodeStyleActiveList.length; i += 1) {
(nodeStyleActiveList[i] as any).style.backgroundColor =
palette.common.black;
(nodeStyleActiveList[i] as any).style.color =
palette.secondary.contrastText;
}
if (
document.getElementsByClassName('ace_gutter-cell')[
selection.cursor.row
] as any
) {
const nodeStyleActive = (document.getElementsByClassName(
'ace_gutter-cell'
)[selection.cursor.row] as any).style;
nodeStyleActive.backgroundColor = palette.primary.main;
nodeStyleActive.color = palette.secondary.contrastText;
}
}}
annotations={editorState.annotations}
markers={editorState.markers}
/>
<Box p={1} flexGrow={0} className={classes.fullScreenGrid}>
<Tooltip
title="Full Screen (Press Escape to End)"
placement="bottom"
TransitionComponent={Fade}
TransitionProps={{ timeout: 500 }}
arrow
>
<AceEditor
mode="yaml"
theme="cobalt"
name="code"
width="100%"
height="100%"
maxLines={12000}
minLines={1}
highlightActiveLine={false}
readOnly={readOnly}
tabSize={2}
wrapEnabled
ref={YamlAce}
showGutter
onChange={onEditorChange}
showPrintMargin={false}
enableBasicAutocompletion
enableSnippets
enableLiveAutocompletion
value={editorState.content}
editorProps={{
$blockScrolling: Infinity,
$useWorker: true,
}}
onLoad={(editor) => {
editor.setReadOnly(readOnly);
editor.setOptions({
fontFamily: 'monospace',
highlightGutterLine: false,
autoScrollEditorIntoView: true,
tooltipFollowsMouse: true,
displayIndentGuides: false,
});
editor.focus();
editor.setHighlightSelectedWord(true);
editor.session.setFoldStyle('markbeginend');
editor.setShowFoldWidgets(true);
editor.setAnimatedScroll(true);
editor.setShowInvisibles(false);
editor.setFontSize('0.98rem');
editor.container.style.background = palette.common.black;
editor.container.style.lineHeight = '160%';
const nodeStyle = (document.getElementsByClassName(
'ace_gutter'
)[0] as any).style;
nodeStyle.color = palette.secondary.contrastText;
nodeStyle.borderRight = 0;
nodeStyle.background = palette.common.black;
}}
onCursorChange={(selection) => {
(YamlAce.current!.editor as any).setOptions({
autoScrollEditorIntoView: true,
tooltipFollowsMouse: true,
});
const nodeStyleActiveList = document.getElementsByClassName(
'ace_gutter-cell'
);
for (let i = 0; i < nodeStyleActiveList.length; i += 1) {
(nodeStyleActiveList[i] as any).style.backgroundColor =
palette.common.black;
(nodeStyleActiveList[i] as any).style.color =
palette.secondary.contrastText;
}
if (
document.getElementsByClassName('ace_gutter-cell')[
selection.cursor.row
] as any
) {
const nodeStyleActive = (document.getElementsByClassName(
'ace_gutter-cell'
)[selection.cursor.row] as any).style;
nodeStyleActive.backgroundColor = palette.primary.main;
nodeStyleActive.color = palette.secondary.contrastText;
}
}}
annotations={editorState.annotations}
markers={editorState.markers}
<Button
variant="outlined"
className={classes.editorButtonFullScreen}
onClick={fullscreentrigger}
startIcon={
<img
src="/icons/fullscreen.svg"
alt="Full Screen"
color={palette.secondary.contrastText}
className={classes.fullScreenIcon}
/>
}
/>
</Box>
<Box p={1} flexGrow={0} className={classes.fullScreenGrid}>
<Tooltip
title="Full Screen (Press Escape to End)"
placement="bottom"
TransitionComponent={Fade}
TransitionProps={{ timeout: 500 }}
arrow
>
<Button
variant="outlined"
className={classes.editorButtonFullScreen}
onClick={fullscreentrigger}
startIcon={
<img
src="/icons/fullscreen.svg"
alt="Full Screen"
color={palette.secondary.contrastText}
className={classes.fullScreenIcon}
/>
}
/>
</Tooltip>
</Box>
</Tooltip>
</Box>
</div>
<div className={classes.extraSpace} />
</div>
);
};

View File

@ -52,14 +52,11 @@ const useStyles = makeStyles((theme: Theme) => ({
justifyContent: 'space-between',
},
editorContainer: {
marginTop: theme.spacing(4),
},
editor: {
overflowY: 'auto',
margin: theme.spacing(2, 0),
height: '40vh',
editorGrid: {
overflow: 'auto',
height: '50vh',
width: '100%',
'&::-webkit-scrollbar': {
width: '0.2em',
},
@ -69,28 +66,6 @@ const useStyles = makeStyles((theme: Theme) => ({
'&::-webkit-scrollbar-thumb': {
backgroundColor: theme.palette.primary.main,
},
[theme.breakpoints.down('xl')]: {
height: '84vh',
},
[theme.breakpoints.down('lg')]: {
height: '56vh',
},
[theme.breakpoints.down('md')]: {
height: '49vh',
},
[theme.breakpoints.down('sm')]: {
height: '40vh',
},
[theme.breakpoints.down('xs')]: {
height: '30vh',
},
},
extraSpace: {
backgroundColor: theme.palette.common.black,
height: '2rem',
width: '100%',
},
editorButtons: {
@ -257,6 +232,7 @@ const useStyles = makeStyles((theme: Theme) => ({
fullWidth: {
width: '100%',
height: '100%',
},
fullScreenIcon: {

View File

@ -9,20 +9,20 @@ import React, {
} from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { constants } from '../../../constants';
import {
GET_CLUSTER,
GET_IMAGE_REGISTRY,
LIST_IMAGE_REGISTRY,
} from '../../../graphql';
import { ImageRegistryInfo } from '../../../models/redux/image_registry';
import useActions from '../../../redux/actions';
import * as AlertActions from '../../../redux/actions/alert';
import * as WorkflowActions from '../../../redux/actions/workflow';
import * as ImageRegistryActions from '../../../redux/actions/image_registry';
import * as WorkflowActions from '../../../redux/actions/workflow';
import { RootState } from '../../../redux/reducers';
import { getProjectID, getProjectRole } from '../../../utils/getSearchParams';
import useStyles from './styles';
import { ImageRegistryInfo } from '../../../models/redux/image_registry';
import { constants } from '../../../constants';
interface Cluster {
cluster_name: string;

View File

@ -100,11 +100,11 @@ const WorkflowPreview: React.FC<WorkflowPreviewProps> = ({
for (let j = 0; j < updatedSteps[i].length; j++) {
data.nodes.push({
id: k.toString(),
class: `${'pending'} ${'steps'}`,
class: `${'succeeded'} ${'steps'}`,
label: createLabel({
label: updatedSteps[i][j].name,
tooltip: updatedSteps[i][j].name,
phase: 'pending',
phase: 'succeeded',
horizontal,
}),
labelType:
@ -120,7 +120,7 @@ const WorkflowPreview: React.FC<WorkflowPreviewProps> = ({
label: createLabel({
label: updatedSteps[i][0].name,
tooltip: updatedSteps[i][0].name,
phase: 'pending',
phase: 'succeeded',
horizontal,
}),
labelType:
@ -148,7 +148,7 @@ const WorkflowPreview: React.FC<WorkflowPreviewProps> = ({
data.links.push({
source: nodeID.toString(),
target: (nodeID + j + 1).toString(),
class: 'pending',
class: 'succeeded',
config: {
arrowhead:
updatedSteps[i][0].name !== 'StepGroup'
@ -170,7 +170,7 @@ const WorkflowPreview: React.FC<WorkflowPreviewProps> = ({
data.links.push({
source: (nodeID + j + 1).toString(),
target: (nodeID + updatedSteps[i].length + 1).toString(),
class: 'pending',
class: 'succeeded',
config: {
arrowhead:
updatedSteps[i][0].name !== 'StepGroup'
@ -191,7 +191,7 @@ const WorkflowPreview: React.FC<WorkflowPreviewProps> = ({
data.links.push({
source: nodeID.toString(),
target: (nodeID + 1).toString(),
class: 'pending',
class: 'succeeded',
config: {
arrowhead:
updatedSteps[i][0].name !== 'StepGroup' ? 'undirected' : 'vee',

View File

@ -18,7 +18,7 @@ const useStyles = makeStyles((theme: Theme) => ({
cursor: 'pointer',
fill: 'none',
'& circle': {
fill: theme.palette.status.pending.text,
fill: theme.palette.status.completed.text,
},
'& g.label g': {
transform: (props: StyleProps) =>
@ -31,20 +31,20 @@ const useStyles = makeStyles((theme: Theme) => ({
fill: theme.palette.text.primary,
},
},
'& path.pendingIcon': {
'& path.succeededIcon': {
transform: (props: StyleProps) =>
`scale(1.8) translate(-5px, ${props.horizontal ? -3.6 : -2.5}px)`,
`scale(1.8) translate(-5px, ${props.horizontal ? -3.6 : -1}px)`,
},
'& g.StepGroup.Pending': {
fill: theme.palette.status.pending.text,
'& g.StepGroup.Succeeded': {
fill: theme.palette.status.completed.text,
},
},
// Styles for edges
'& g g.edgePaths': {
'& g.pending': {
fill: theme.palette.status.pending.text,
stroke: theme.palette.status.pending.text,
'& g.succeeded': {
fill: theme.palette.status.completed.text,
stroke: theme.palette.status.completed.text,
},
},
},

View File

@ -593,7 +593,8 @@ const TuneWorkflow = forwardRef((_, ref) => {
onClose={() => {
setYAMLModal(false);
}}
width="60%"
width="90%"
height="90%"
modalActions={
<ButtonOutlined
onClick={() => {
@ -643,6 +644,7 @@ const TuneWorkflow = forwardRef((_, ref) => {
<YamlEditor
content={manifest}
filename={workflow.name}
className={classes.editor}
readOnly={false}
setButtonState={(btnState: boolean) => {
setYamlValid(btnState);

View File

@ -151,6 +151,11 @@ const useStyles = makeStyles((theme) => ({
margin: theme.spacing(8, 5, 5, 5),
},
// Editor
editor: {
height: '100%',
},
// Confirmation Modal
confirmDiv: {
margin: 'auto',