Skip to content

Commit

Permalink
feat: changes to the package manager config and the files artifact vi…
Browse files Browse the repository at this point in the history
…ew (#1322)

## Description:
This change improves the UX of the package manager and the files
artifact view. It's not a breaking change

## Is this change user facing?
YES

## References (if applicable):
<!-- Add relevant Github Issues, Discord threads, or other helpful
information. -->
  • Loading branch information
adschwartz committed Sep 18, 2023
1 parent 49a9c34 commit e2b0d2b
Show file tree
Hide file tree
Showing 11 changed files with 20,173 additions and 24,438 deletions.
43,807 changes: 19,485 additions & 24,322 deletions engine/frontend/package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions engine/frontend/package.json
Expand Up @@ -12,6 +12,7 @@
"@chakra-ui/react": "^2.8.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@monaco-editor/react": "^4.5.2",
"@tailwindcss/typography": "^0.5.10",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
Expand All @@ -24,9 +25,12 @@
"google-protobuf": "^3.21.2",
"js-yaml": "^4.1.0",
"kurtosis-sdk": "../../api/typescript/",
"monaco-editor": "^0.39.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.7",
"react-monaco-editor": "^0.54.0",
"react-object-input": "^0.2.1",
"react-router": "^6.13.0",
"react-router-dom": "^6.14.1",
"react-scripts": "5.0.1",
Expand Down
213 changes: 213 additions & 0 deletions engine/frontend/src/component/CodeEditor.js
@@ -0,0 +1,213 @@
import React, {useEffect, useMemo, useRef, useState} from "react";
import {Box, Button, useClipboard} from "@chakra-ui/react";
import useWindowDimensions from "../utils/windowheight";
import Editor from "@monaco-editor/react";

export const CodeEditor = (
dataCallback,
readOnly = false,
fullFileName = "json_field.json",
languages = ["json"],
defaultWidthPx = 500,
defaultState = languages.includes("json") ? "{\n}" : "",
autoFormat = false,
) => {
// https://github.com/microsoft/monaco-editor/blob/main/webpack-plugin/README.md#options
const [value, setValue] = useState(defaultState)
const contentClipboard = useClipboard("");
const monacoRef = useRef(null);
const dimensions = useWindowDimensions();
const originalReadOnlySetting = useRef(readOnly)
const [readOnlySetting, setReadOnlySetting] = useState(readOnly)
const [formatCode, setFormatCode] = useState(false)

// TODO: This could lead to bugs in the future:
// This number depends on the version of Monaco! Use actual enum instead.
const monacoReadOnlyEnumId = 86;

// TODO: Add a promise to getEditor()
const getEditor = () => {
if (!monacoRef.current) return null;
return monacoRef.current.editor.getEditors()[0];
}

const isEditorReadOnly = () => {
try {
return getEditor().getOption(monacoReadOnlyEnumId)
} catch (e) {
return undefined
}
}
const [monacoReadOnlySettingHasChanged, setMonacoReadOnlySettingHasChangedHasChanged] = useState(false)

function attachOptionsChangeListener() {
getEditor().onDidChangeConfiguration((event) => {
if (event.hasChanged(monacoReadOnlyEnumId)) {
setMonacoReadOnlySettingHasChangedHasChanged(true)
}
});
}

useEffect(() => {
if (getEditor()) {
console.log("Changing readOnly in monaco to:", readOnlySetting)
getEditor().updateOptions({
readOnly: readOnlySetting,
})
}
}, [readOnlySetting])

useEffect(() => {
if (formatCode) {
if (isEditorReadOnly()) {
console.log("Cannot format with readonly=true, requesting to set readOnly=false")
setReadOnlySetting(false)
} else {
if (getEditor()) {
getEditor()
.getAction('editor.action.formatDocument')
.run()
.then(() => {
console.log(`Formatting finished running. Setting readonly=${originalReadOnlySetting.current}`)
setReadOnlySetting(originalReadOnlySetting.current)
setFormatCode(false)
});
}
}
}
}, [formatCode, monacoReadOnlySettingHasChanged])

// Start by manually setting the content of the editor. From hereafter user interaction will update it:
useEffect(() => {
handleEditorChange(value)
}, [])

useEffect(() => {
contentClipboard.setValue(value)
// Resize view on content change
updateWindowHeightBasedOnContent();
}, [value])

// Resize view on window change
useEffect(() => {
if (getEditor()) {
getEditor().layout({width: defaultWidthPx, height: getEditor().getContentHeight()});
getEditor().layout()
}
}, [dimensions])

const updateWindowHeightBasedOnContent = () => {
if (getEditor()) {
const contentHeight = Math.min(1000, getEditor().getContentHeight());
getEditor().layout({width: defaultWidthPx, height: contentHeight});
getEditor().layout()
}
};

const saveTextAsFile = (text, fileName) => {
const blob = new Blob([text], {type: "text/plain"});
const downloadLink = document.createElement("a");
downloadLink.download = fileName;
downloadLink.innerHTML = "Download File";
if (window.webkitURL) {
// No need to add the download element to the DOM in Webkit.
downloadLink.href = window.webkitURL.createObjectURL(blob);
} else {
downloadLink.href = window.URL.createObjectURL(blob);
downloadLink.onclick = (event) => {
if (event.target) {
document.body.removeChild(event.target);
}
};
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
}

downloadLink.click();

if (window.webkitURL) {
window.webkitURL.revokeObjectURL(downloadLink.href);
} else {
window.URL.revokeObjectURL(downloadLink.href);
}
};

function handleEditorChange(value) {
setValue(value)
dataCallback(value)
}

function handleEditorDidMount(editor, monaco) {
monacoRef.current = monaco;
updateWindowHeightBasedOnContent();
attachOptionsChangeListener()
if (autoFormat) handleCodeFormat();
}

function handleDownload() {
saveTextAsFile(value, fullFileName)
}

function handleCodeFormat() {
setFormatCode(true)
}

// TODO: We can use this to display error messages
// function handleEditorValidation(markers) {
// // model markers
// // markers.forEach(marker => console.log('onValidate:', marker.message));
// }

const isNotFormattable = () => {
return !languages.includes("json")
}

return (
<Box
border="1px"
borderColor='gray.700'
borderRadius="7"
margin={"1px"}
padding={1}
>
<Editor
margin={1}
defaultLanguage="json"
value={value}
theme={"vs-dark"}
onMount={handleEditorDidMount}
onChange={handleEditorChange}
// onValidate={handleEditorValidation}
options={{
automaticLayout: true,
selectOnLineNumbers: true,
languages: languages,
readOnly: readOnlySetting,
minimap: {
enabled: false
},
scrollBeyondLastLine: false
}}
/>
<Button
margin={1}
onClick={contentClipboard.onCopy}
>
{contentClipboard.hasCopied ? "Copied!" : "Copy"}
</Button>
<Button
margin={1}
onClick={handleDownload}
>
Download
</Button>
<Button
margin={1}
onClick={handleCodeFormat}
isDisabled={isNotFormattable()}
>
Format
</Button>
</Box>
)
}
18 changes: 9 additions & 9 deletions engine/frontend/src/component/EnclaveInfo.js
Expand Up @@ -34,7 +34,7 @@ const renderServices = (services, handleClick) => {

return services.map((service) => {
return (
<div className="border-4 bg-[#171923] text-lg align-middle text-center h-16 p-3 text-[#24BA27]"
<div className="border-2 bg-[#171923] text-lg align-middle text-center h-16 p-3 text-[#24BA27]"
onClick={() => handleClick(service, services)}>
<div> {service.name} </div>
</div>
Expand All @@ -55,15 +55,15 @@ const renderFileArtifacts = (file_artifacts, handleFileArtifactClick) => {

return file_artifacts.map((file_artifact) => {
return (
<div className="border-4 bg-[#171923] text-lg align-middle text-center h-16 p-3 text-[#24BA27]"
<div className="border-2 bg-[#171923] text-lg align-middle text-center h-16 p-3 text-[#24BA27]"
onClick={() => handleFileArtifactClick(file_artifact.name, file_artifacts)}>
<div>{file_artifact.name}</div>
</div>
)
})
}

const EncalveInfo = ({enclaves}) => {
const EnclaveInfo = ({enclaves}) => {
const navigate = useNavigate();
const {appData} = useAppContext()

Expand Down Expand Up @@ -110,14 +110,14 @@ const EncalveInfo = ({enclaves}) => {

const EnclaveInfoComponent = ({services, fileArtifacts, handleServiceClick, handleFileArtifactClick}) => (
<div className='flex flex-col h-[calc(100vh-3rem)] space-y-1 overflow-auto'>
<div className="flex flex-col h-1/2 min-h-1/2 border-8">
<Heading content={"Services"} size={"text-xl"}/>
<div className="flex flex-col h-1/2 min-h-1/2 border-2">
<Heading color={"text-white"} content={"Services"} size={"text-xl"}/>
<div className="overflow-auto space-y-2">
{renderServices(services, handleServiceClick)}
</div>
</div>
<div className="flex flex-col h-[46%] border-8">
<Heading content={"File Artifacts"} size={"text-xl"} padding={"p-1"}/>
<div className="flex flex-col h-[46%] border-2">
<Heading color={"text-white"} content={"File Artifacts"} size={"text-xl"} padding={"p-1"}/>
<div className="overflow-auto space-y-2">
{renderFileArtifacts(fileArtifacts, handleFileArtifactClick)}
</div>
Expand All @@ -133,7 +133,7 @@ const EncalveInfo = ({enclaves}) => {
renderList={() => renderEnclaves(enclaves, handleLeftPanelClick)}
/>

<div className="flex bg-white w-[calc(100vw-39rem)] flex-col space-y-5">
<div className="flex bg-[#171923] w-[calc(100vw-39rem)] flex-col space-y-5">
<div className="h-[3rem] flex items-center justify-center m-2">
<Heading content={name}/>
</div>
Expand All @@ -153,4 +153,4 @@ const EncalveInfo = ({enclaves}) => {
)
}

export default EncalveInfo;
export default EnclaveInfo;

0 comments on commit e2b0d2b

Please sign in to comment.