Skip to content
Open
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sentinel-hub/evalscript-code-editor",
"version": "1.0.44",
"version": "1.0.45",
"description": "",
"type": "module",
"main": "dist/index.cjs",
Expand Down
136 changes: 98 additions & 38 deletions src/components/CodeEditor/CodeEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,21 @@ export const CodeEditor = ({
runningEvalscriptButtonText = "Running evalscript",
readOnlyMessage = "Editor is in read only mode",
runEvalscriptOnShortcut = false,
language = "javascript",
isEditable = true,
}) => {
const monacoEditorDOMRef = useRef();
const monacoRef = useRef();
const headerEditorRef = useRef();
const editorRef = useRef();
const editorWindowRef = useRef();
const [shouldTriggerRunEvalscriptAnimation, setShouldTriggerRunEvalscriptAnimation] = useState(false);
const [isDarkTheme, setIsDarkTheme] = useState(defaultEditorTheme === "dark" ? true : false);
const [
shouldTriggerRunEvalscriptAnimation,
setShouldTriggerRunEvalscriptAnimation,
] = useState(false);
const [isDarkTheme, setIsDarkTheme] = useState(
defaultEditorTheme === "dark" ? true : false
);

const {
editorPosition,
Expand All @@ -173,7 +180,7 @@ export const CodeEditor = ({
useEffect(() => {
let MONACO_EDITOR_CONFIG = {
value,
language: "javascript",
language: language,
wordWrap: true,
fontSize: isDocked ? 12 : 14,
automaticLayout: true,
Expand Down Expand Up @@ -218,15 +225,23 @@ export const CodeEditor = ({
});

if (runEvalscriptOnShortcut && onRunEvalscriptClick) {
editorRef.current.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, () => {
setShouldTriggerRunEvalscriptAnimation(true);
onRunEvalscriptClick(editorRef.current.getValue());
});
editorRef.current.addCommand(
monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
() => {
setShouldTriggerRunEvalscriptAnimation(true);
onRunEvalscriptClick(editorRef.current.getValue());
}
);
}

const messageContribution = editorRef.current.getContribution("editor.contrib.messageController");
const messageContribution = editorRef.current.getContribution(
"editor.contrib.messageController"
);
editorRef.current.onDidAttemptReadOnlyEdit(() => {
messageContribution.showMessage(readOnlyMessage, editorRef.current.getPosition());
messageContribution.showMessage(
readOnlyMessage,
editorRef.current.getPosition()
);
});

monacoRef.current = monaco;
Expand All @@ -239,6 +254,27 @@ export const CodeEditor = ({
});
}, [isDocked]);

useEffect(() => {
if (monacoRef.current !== undefined && editorRef.current !== undefined) {
monacoRef.current.editor.setModelLanguage(
editorRef.current.getModel(),
language
);

if (!isEditable) {
const messageContribution = editorRef.current.getContribution(
"editor.contrib.messageController"
);
editorRef.current.onDidAttemptReadOnlyEdit(() => {
messageContribution.showMessage(
readOnlyMessage,
editorRef.current.getPosition()
);
});
}
}
}, [language]);

useEffect(() => {
if (!editorRef.current) {
return;
Expand Down Expand Up @@ -266,11 +302,9 @@ export const CodeEditor = ({
return;
}

if (isReadOnly) {
editorRef.current.updateOptions({ readOnly: true });
} else {
editorRef.current.updateOptions({ readOnly: false });
}
editorRef.current.updateOptions({
readOnly: isReadOnly,
});
}, [isReadOnly, editorRef.current]);

const debounce = useCallback((func, wait, immediate) => {
Expand Down Expand Up @@ -310,7 +344,11 @@ export const CodeEditor = ({
: monacoRef.current.MarkerSeverity.Warning,
};
});
monacoRef.current.editor.setModelMarkers(editorRef.current.getModel(), "test", errors);
monacoRef.current.editor.setModelMarkers(
editorRef.current.getModel(),
"test",
errors
);
}, 500);

function toggleTheme() {
Expand All @@ -320,7 +358,11 @@ export const CodeEditor = ({
if (isDocked) {
return (
<ThemeProvider
theme={isDarkTheme ? { ...variables, ...themeDark.styles } : { ...variables, ...themeLight.styles }}
theme={
isDarkTheme
? { ...variables, ...themeDark.styles }
: { ...variables, ...themeLight.styles }
}
>
<CodeEditorWindowDocked ref={editorWindowRef}>
<CodeEditorTopPanel ref={headerEditorRef}>
Expand All @@ -330,7 +372,9 @@ export const CodeEditor = ({
</CodeEditorIcon>
</CodeEditorTopPanel>
<MonacoEditor ref={monacoEditorDOMRef}>
{isReadOnly && <ReadonlyOverlay isDarkTheme={isDarkTheme}></ReadonlyOverlay>}
{isReadOnly && isEditable && (
<ReadonlyOverlay isDarkTheme={isDarkTheme}></ReadonlyOverlay>
)}
</MonacoEditor>
</CodeEditorWindowDocked>
</ThemeProvider>
Expand All @@ -339,7 +383,11 @@ export const CodeEditor = ({

return ReactDOM.createPortal(
<ThemeProvider
theme={isDarkTheme ? { ...variables, ...themeDark.styles } : { ...variables, ...themeLight.styles }}
theme={
isDarkTheme
? { ...variables, ...themeDark.styles }
: { ...variables, ...themeLight.styles }
}
>
<CodeEditorWindow
zIndex={zIndex}
Expand Down Expand Up @@ -370,33 +418,45 @@ export const CodeEditor = ({
</>
)}
</CodeEditorTopPanel>
<MonacoEditor style={{ height: editorSize.height - 96 }} ref={monacoEditorDOMRef}>
{isReadOnly && <ReadonlyOverlay isDarkTheme={isDarkTheme}></ReadonlyOverlay>}
<MonacoEditor
style={{ height: editorSize.height - 96 }}
ref={monacoEditorDOMRef}
>
{isReadOnly && isEditable && (
<ReadonlyOverlay isDarkTheme={isDarkTheme}></ReadonlyOverlay>
)}
</MonacoEditor>
<CodeEditorBottomPanel>
<ButtonPrimary
onClick={() => {
setShouldTriggerRunEvalscriptAnimation(true);
onRunEvalscriptClick(editorRef.current.getValue());
}}
disabled={isReadOnly}
>
{shouldTriggerRunEvalscriptAnimation ? (
<>
{runningEvalscriptButtonText}
<SuccessIcon />
</>
) : (
runEvalscriptButtonText
)}
</ButtonPrimary>
{isEditable ? (
<ButtonPrimary
onClick={() => {
setShouldTriggerRunEvalscriptAnimation(true);
onRunEvalscriptClick(editorRef.current.getValue());
}}
disabled={isReadOnly}
>
{shouldTriggerRunEvalscriptAnimation ? (
<>
{runningEvalscriptButtonText}
<SuccessIcon />
</>
) : (
runEvalscriptButtonText
)}
</ButtonPrimary>
) : (
<div />
)}

<CodeEditorIcon onMouseDown={handleResizeMouseDown} style={{ cursor: "nwse-resize", zIndex: 0 }}>
<CodeEditorIcon
onMouseDown={handleResizeMouseDown}
style={{ cursor: "nwse-resize", zIndex: 0 }}
>
<CgArrowsExpandLeft />
</CodeEditorIcon>
</CodeEditorBottomPanel>
</CodeEditorWindow>
</ThemeProvider>,
document.getElementById(portalId),
document.getElementById(portalId)
);
};
99 changes: 81 additions & 18 deletions src/components/Wrapper/Wrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,40 @@ import {
import "./wrapper.css";
export default function Wrapper() {
const [isReadOnly, setIsReadOnly] = useState(false);
const [isEvalscriptSelected, setIsEvalscriptSelected] = useState(true);
const [processGraph] = useState({
load2: {
process_id: "load_collection",
arguments: {
id: "sentinel-2-l2a",
spatial_extent: {},
temporal_extent: ["2022-03-26T00:00:00Z", "2022-03-26T23:59:59Z"],
bands: ["B08", "B04", "B03"],
resampling: "BICUBIC",
},
},
highlight: {
process_id: "highlight_compression",
arguments: {
data: {
from_node: "load2",
},
maxInput: 0.4,
clipInput: 0.8,
maxOutput: 1,
},
},
save5: {
process_id: "save_result",
arguments: {
format: "PNG",
data: {
from_node: "highlight",
},
},
result: true,
},
});
const [evalscript, setEvalscript] =
useState(`let ndvi = (B08 - B04) / (B08 + B04);

Expand Down Expand Up @@ -138,36 +172,65 @@ export default function Wrapper() {
return (
<div
style={{
height: "200vh",
height: "100vh",
display: "flex",
alignItems: "center",
width: 400,
alignItems: "flex-start",
width: 600,
background: "black",
}}
className="panel"
>
<textarea name="" id="" value="asd" cols="30" rows="10"></textarea>
<div style={{ height: 400 }}>
<CodeEditor
themeLight={themeEoBrowserLight}
themeDark={themeEoBrowserDark}
value={evalscript}
onChange={(code) => setEvalscript(code)}
editorTheme="dark"
portalId="root"
onRunEvalscriptClick={() => console.log("running function from shortcut! Ctrl+Enter")}
runEvalscriptOnShortcut
isReadOnly={isReadOnly}
readOnlyMessage={`Editor is in read only mode. Untick "Load script from URL" to enable it again.`}
/>
{/* <textarea name="" id="" value="asd" cols="30" rows="10"></textarea> */}
<div style={{ height: "60vh" }}>
<h1 style={{ color: "white" }}>
Wrapper to simulate parent div in apps like EOB and RB
Wrapper to simulate parent div in apps like EOB and CB
</h1>

<button onClick={() => setIsReadOnly((prev) => !prev)}>
Toggle read only
</button>
<button onClick={() => updateCode()}>Inject Evalscript</button>
<button onClick={() => setIsEvalscriptSelected(!isEvalscriptSelected)}>
Switch between JSON and Evalscript
</button>
{isEvalscriptSelected ? (
<CodeEditor
themeLight={themeEoBrowserLight}
themeDark={themeEoBrowserDark}
value={evalscript}
isReadOnly={isReadOnly}
isEditable={true}
language="javascript"
editorTheme="dark"
portalId="root"
onChange={(code) => {
try {
JSON.parse(code);
} catch (error) {
if (isEvalscriptSelected) {
setEvalscript(code);
}
}
}}
onRunEvalscriptClick={() =>
console.log("running function from shortcut! Ctrl+Enter")
}
runEvalscriptOnShortcut
readOnlyMessage={`Editor is in read only mode. Untick "Load script from URL" to enable it again.`}
/>
) : (
<CodeEditor
themeLight={themeEoBrowserLight}
themeDark={themeEoBrowserDark}
value={JSON.stringify(processGraph, null, "\t")}
isReadOnly={true}
isEditable={false}
language="json"
editorTheme="dark"
portalId="root"
onChange={() => {}}
/>
)}
</div>
</div>
);
Expand Down