mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
PE-71 close (#12)
* fixed expand issues * removed expand * can close the file, and min 5 lines are * removed older file
This commit is contained in:
@@ -279,6 +279,18 @@ input[type="checkbox"] {
|
||||
.save-disabled:hover {
|
||||
background-color: #aaaea7;
|
||||
}
|
||||
.close-enabled {
|
||||
color: white;
|
||||
background-color: #9e0000;
|
||||
}
|
||||
.close-disabled {
|
||||
color: rgb(52, 52, 52);
|
||||
background-color: #aaaea7;
|
||||
cursor: default !important;
|
||||
}
|
||||
.close-disabled:hover {
|
||||
background-color: #aaaea7;
|
||||
}
|
||||
.message {
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
|
||||
+58
-15
@@ -1,7 +1,7 @@
|
||||
import * as React from "react";
|
||||
import { RendererContext, RendererOpts, LineStateType } from "../types";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import { GlobalModel } from "../model";
|
||||
import { GlobalModel, GlobalCommandRunner } from "../model";
|
||||
|
||||
function renderCmdText(text: string): any {
|
||||
return <span>⌘{text}</span>;
|
||||
@@ -34,28 +34,28 @@ class SourceCodeRenderer extends React.Component<
|
||||
super(props);
|
||||
this.editorRef = React.createRef();
|
||||
this.state = {
|
||||
code: "",
|
||||
code: null,
|
||||
language: "",
|
||||
languages: [],
|
||||
selectedLanguage: "",
|
||||
isSave: false,
|
||||
isClosed: false,
|
||||
editorHeight: props.savedHeight,
|
||||
message: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
console.dir(this.props);
|
||||
this.filePath = this.props.lineState["prompt:file"];
|
||||
const { screenId, lineId } = this.props.context;
|
||||
this.cacheKey = `${screenId}-${lineId}-${this.filePath}`;
|
||||
const code = SourceCodeRenderer.codeCache.get(this.cacheKey);
|
||||
if (code) {
|
||||
this.setState({ code });
|
||||
this.setState({ code, isClosed: this.props.lineState["prompt:closed"] });
|
||||
} else
|
||||
this.props.data.text().then((code) => {
|
||||
this.originalData = code;
|
||||
this.setState({ code });
|
||||
this.setState({ code, isClosed: this.props.lineState["prompt:closed"] });
|
||||
SourceCodeRenderer.codeCache.set(this.cacheKey, code);
|
||||
});
|
||||
}
|
||||
@@ -79,10 +79,14 @@ class SourceCodeRenderer extends React.Component<
|
||||
}
|
||||
this.setEditorHeight();
|
||||
editor.onKeyDown((e) => {
|
||||
if (e.code === "KeyS" && (e.ctrlKey || e.metaKey)) {
|
||||
if (e.code === "KeyS" && (e.ctrlKey || e.metaKey) && this.state.isSave) {
|
||||
e.preventDefault();
|
||||
this.doSave();
|
||||
}
|
||||
if (e.code === "KeyD" && (e.ctrlKey || e.metaKey) && !this.state.isSave) {
|
||||
e.preventDefault();
|
||||
this.doClose();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -99,9 +103,9 @@ class SourceCodeRenderer extends React.Component<
|
||||
};
|
||||
|
||||
doSave = () => {
|
||||
if (!this.state.isSave) return;
|
||||
const { screenId, lineId } = this.props.context;
|
||||
const encodedCode = new TextEncoder().encode(this.state.code);
|
||||
debugger;
|
||||
GlobalModel.writeRemoteFile(screenId, lineId, this.filePath, encodedCode, { useTemp: true })
|
||||
.then(() => {
|
||||
this.originalData = this.state.code;
|
||||
@@ -117,6 +121,31 @@ class SourceCodeRenderer extends React.Component<
|
||||
});
|
||||
};
|
||||
|
||||
doClose = () => {
|
||||
if (this.state.isSave) return;
|
||||
const { screenId, lineId } = this.props.context;
|
||||
GlobalCommandRunner.setLineState(screenId, lineId, { ...this.props.lineState, "prompt:closed": true }, false)
|
||||
.then(() => {
|
||||
this.setState({
|
||||
isClosed: true,
|
||||
message: { status: "success", text: `Closed. This editor is now read-only` },
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.setEditorHeight();
|
||||
}, 100);
|
||||
setTimeout(() => {
|
||||
this.setState({ message: null });
|
||||
}, 3000);
|
||||
})
|
||||
.catch((e) => {
|
||||
this.setState({ message: { status: "error", text: e.message } });
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({ message: null });
|
||||
}, 3000);
|
||||
});
|
||||
};
|
||||
|
||||
handleEditorChange = (code) => {
|
||||
SourceCodeRenderer.codeCache.set(this.cacheKey, code);
|
||||
this.setState({ code }, () => {
|
||||
@@ -128,18 +157,18 @@ class SourceCodeRenderer extends React.Component<
|
||||
setEditorHeight = () => {
|
||||
const fullWindowHeight = parseInt(this.props.opts.maxSize.height);
|
||||
let _editorHeight = fullWindowHeight;
|
||||
if (this.props.readOnly) {
|
||||
const noOfLines = this.state.code.split("\n").length;
|
||||
if (this.props.readOnly || this.state.isClosed) {
|
||||
const noOfLines = Math.max(this.state.code.split("\n").length, 5);
|
||||
_editorHeight = Math.min(noOfLines * GlobalModel.termFontSize.get() * 1.5 + 10, fullWindowHeight);
|
||||
}
|
||||
this.setState({ editorHeight: _editorHeight }, () => this.props.scrollToBringIntoViewport());
|
||||
};
|
||||
|
||||
render() {
|
||||
const { opts, exitcode } = this.props;
|
||||
const { lang, code, isSave } = this.state;
|
||||
const { opts, exitcode, readOnly } = this.props;
|
||||
const { lang, code, isSave, isClosed } = this.state;
|
||||
|
||||
if (!code)
|
||||
if (code == null)
|
||||
return <div className="renderer-container code-renderer" style={{ height: this.props.savedHeight }} />;
|
||||
|
||||
if (exitcode === 1)
|
||||
@@ -169,7 +198,7 @@ class SourceCodeRenderer extends React.Component<
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
readOnly: this.props.readOnly,
|
||||
readOnly: readOnly || isClosed,
|
||||
keybindings: [
|
||||
{
|
||||
key: "ctrl+s",
|
||||
@@ -197,13 +226,27 @@ class SourceCodeRenderer extends React.Component<
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{!this.props.readOnly && (
|
||||
{!readOnly && !isClosed && (
|
||||
<div className="cmd-hints" style={{ minWidth: "6rem", maxWidth: "6rem", marginLeft: "-18px" }}>
|
||||
<div
|
||||
onClick={this.doSave}
|
||||
className={`hint-item ${isSave ? "save-enabled" : "save-disabled"}`}
|
||||
>
|
||||
{`save`} {renderCmdText("S")}
|
||||
{`save (`}
|
||||
{renderCmdText("S")}
|
||||
{`)`}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!readOnly && !isClosed && (
|
||||
<div className="cmd-hints" style={{ minWidth: "6rem", maxWidth: "6rem", marginLeft: "-18px" }}>
|
||||
<div
|
||||
onClick={this.doClose}
|
||||
className={`hint-item ${!isSave ? "close-enabled" : "close-disabled"}`}
|
||||
>
|
||||
{`close (`}
|
||||
{renderCmdText("D")}
|
||||
{`)`}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
import * as React from "react";
|
||||
import * as mobx from "mobx";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import { RendererContext, RendererOpts } from "../types";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import { GlobalModel } from "../model";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
@mobxReact.observer
|
||||
class SourceCodeRenderer extends React.Component<
|
||||
{
|
||||
data: Blob;
|
||||
cmdstr: String;
|
||||
cwd: String;
|
||||
context: RendererContext;
|
||||
opts: RendererOpts;
|
||||
savedHeight: number;
|
||||
scrollToBringIntoViewport: () => void;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
code: OV<string> = mobx.observable.box("");
|
||||
language: OV<string> = mobx.observable.box("");
|
||||
languages: OV<string[]> = mobx.observable.box([]);
|
||||
selectedLanguage: OV<string> = mobx.observable.box("");
|
||||
isFullWindow: OV<boolean> = mobx.observable.box(false); // load this from opts
|
||||
editorHeight: OV<number> = mobx.observable.box(this.props.savedHeight); // load this from opts
|
||||
editorRef;
|
||||
resizeObserver;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editorRef = React.createRef();
|
||||
console.log(`resetting the code`);
|
||||
this.props.data.text().then((text) => this.code.set(text));
|
||||
}
|
||||
|
||||
componentDidMount() {}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
console.log(`will unmount`);
|
||||
}
|
||||
|
||||
handleEditorDidMount = (editor, monaco) => {
|
||||
// Use a regular expression to match a filename with an extension
|
||||
const extension = this.props.cmdstr.match(/(?:[^\\\/:*?"<>|\r\n]+\.)([a-zA-Z0-9]+)\b/)?.[1] || "";
|
||||
const detectedLanguage = monaco.languages
|
||||
.getLanguages()
|
||||
.find((lang) => lang.extensions && lang.extensions.includes("." + extension));
|
||||
const languages = monaco.languages.getLanguages().map((lang) => lang.id);
|
||||
this.languages.set(languages);
|
||||
if (detectedLanguage) {
|
||||
this.selectedLanguage.set(detectedLanguage.id);
|
||||
this.editorRef.current = editor;
|
||||
const model = editor.getModel();
|
||||
if (model) {
|
||||
monaco.editor.setModelLanguage(model, detectedLanguage.id);
|
||||
this.language.set(detectedLanguage.id);
|
||||
}
|
||||
}
|
||||
this.setEditorHeight();
|
||||
};
|
||||
|
||||
handleLanguageChange = (event) => {
|
||||
const selectedLanguage = event.target.value;
|
||||
this.selectedLanguage.set(selectedLanguage);
|
||||
if (this.editorRef.current) {
|
||||
const model = this.editorRef.current.getModel();
|
||||
if (model) {
|
||||
monaco.editor.setModelLanguage(model, selectedLanguage);
|
||||
this.language.set(selectedLanguage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
toggleFit = () => {
|
||||
this.isFullWindow.set(!this.isFullWindow.get());
|
||||
this.setEditorHeight();
|
||||
setTimeout(() => this.props.scrollToBringIntoViewport(), 350);
|
||||
};
|
||||
|
||||
handleEditorChange = (value, event) => {
|
||||
// editing will always be in fullscreen
|
||||
this.isFullWindow.set(true);
|
||||
this.code.set(value);
|
||||
this.setEditorHeight();
|
||||
setTimeout(() => this.props.scrollToBringIntoViewport(), 350);
|
||||
};
|
||||
|
||||
setEditorHeight = () => {
|
||||
const fullWindowHeight = parseInt(this.props.opts.maxSize.height);
|
||||
let _editorHeight = fullWindowHeight;
|
||||
if (!this.isFullWindow.get()) {
|
||||
const noOfLines = this.code.get().split("\n").length;
|
||||
_editorHeight = Math.min(noOfLines * GlobalModel.termFontSize.get() * 1.5 + 10, fullWindowHeight);
|
||||
}
|
||||
this.editorHeight.set(_editorHeight);
|
||||
};
|
||||
|
||||
render() {
|
||||
let opts = this.props.opts;
|
||||
let lang = this.language.get();
|
||||
let code = this.code.get();
|
||||
if (!code) {
|
||||
return <div className="renderer-container code-renderer" style={{ height: this.props.savedHeight }} />;
|
||||
}
|
||||
return (
|
||||
<div className="renderer-container code-renderer">
|
||||
<div className="scroller" style={{ maxHeight: opts.maxSize.height, paddingBottom: "15px" }}>
|
||||
<Editor
|
||||
theme="hc-black"
|
||||
height={this.editorHeight.get()}
|
||||
defaultLanguage={lang}
|
||||
defaultValue={code}
|
||||
onMount={this.handleEditorDidMount}
|
||||
options={{
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: GlobalModel.termFontSize.get(),
|
||||
fontFamily: "JetBrains Mono",
|
||||
readOnly: this.props.opts.readOnly,
|
||||
}}
|
||||
onChange={this.handleEditorChange}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ position: "absolute", bottom: "-3px", right: 0 }}>
|
||||
<select
|
||||
className="dropdown"
|
||||
value={this.selectedLanguage.get()}
|
||||
onChange={this.handleLanguageChange}
|
||||
style={{ minWidth: "6rem", maxWidth: "6rem", marginRight: "8px" }}
|
||||
>
|
||||
{this.languages.get().map((lang, index) => (
|
||||
<option key={index} value={lang}>
|
||||
{lang}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="cmd-hints" style={{ minWidth: "6rem", maxWidth: "6rem" }}>
|
||||
<div onClick={this.toggleFit} className="hint-item color-white">
|
||||
{this.isFullWindow.get() ? `shrink` : `expand`}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { SourceCodeRenderer };
|
||||
Reference in New Issue
Block a user