<commit_before>import React from "react";

import {ForEach, Renderer, If} from "neutrine/lib/components";
import {SplitPanel, SplitPanelItem} from "neutrine/lib/components";

import {ExplorePanel} from "./ExplorePanel/index.js";
import {MainPanel} from "./MainPanel/index.js";
import {CodeTab} from "./MainPanel/CodeTab.js";
//import {createSandbox} from "../../utils/sandbox.js";

//Build state from props
let buildStateFromProps = function (props) {
    let newState = {
        "tab": "schema", //"readme",
        //"sandbox": createSandbox({"name": "Untitled"}),
        "running": false,
        "rendered": false //To store if sandbox has been rendered
    };
    //Check for initial sandbox data
    //if (typeof props.sandbox === "object" && props.sandbox !== null) {
    //    newState.sandbox = Object.assign(newState.sandbox, props.sandbox);
    //}
    //Return new state
    return newState;
};

//Export sandbox editor class
export class SandboxEditor extends React.Component {
    constructor(props) {
        super(props);
        //Initialize state
        this.state = buildStateFromProps(this.props);
        //Referenced elements
        this.ref = {
            "readme": React.createRef(),
            "schema": React.createRef(),
            "data": React.createRef(),
            "explore": React.createRef()
        };
        //Bind methods
        this.handleTabChange = this.handleTabChange.bind(this);
        this.handleRun = this.handleRun.bind(this);
        this.updateTabContent = this.updateTabContent.bind(this);
        //Bind sandbox methods
        this.getSandbox = this.getSandbox.bind(this);
        this.runSandbox = this.runSandbox.bind(this);
    }
    //Component dod mount --> set tab content
    componentDidMount() {
        return this.updateTabContent();
    }
    //Component did update --> update tab content
    componentDidUpdate() {
        //return this.updateTabContent();
    }
    //Handle tab change
    handleTabChange(key) {
        let self = this;
        if (key === this.state.tab) {
            return null; //Nothing to do
        }
        //Update the state with the current sandbox data and the new tab
        //let sandbox = this.getSandbox();
        return this.getSandbox().then(function (sandbox) {
            return self.props.onSandboxUpdate(sandbox, function () {
                return self.setState({"tab": key}, function () {
                    return self.updateTabContent();
                });
            });
        });
    }
    //Handle run click
    handleRun() {
        return this.runSandbox();
    }
    //Update tab content
    updateTabContent() {
        let sandbox = this.props.sandbox; //Get sandbox
        //Check for schema tab --> set schema value
        if (this.state.tab === "schema") {
            this.ref.schema.current.setValue(sandbox.schema);
        }
        //Check for readme tab --> set readme value
        else if (this.state.tab === "readme" && typeof sandbox.readme === "string") {
            this.ref.readme.current.setValue(sandbox.readme);
        }
    }
    //Run sandbox
    runSandbox(cb) {
        let self = this;
        let rendered = false;
        //let sandbox = this.getSandbox(); //Get current sandbox state
        //Update the state before running the sandbox
        return this.setState({"running": true}, function () {
            return self.getSandbox().then(function (sandbox) {
                return self.ref.explore.current.run(sandbox);
            }).then(function() {
                rendered = true; //Plot rendered
            }).catch(function (error) {
                //Something went wrong rendering the plot
                //console.error(error);
            }).finally(function () {
                //In both cases, running process has been finished
                return self.setState({
                    "running": false,
                    "rendered": rendered
                });
            });
        });
    }
    //Get the current state of the sandbox
    getSandbox() {
        let self = this;
        let sandbox = Object.assign({}, this.props.sandbox); //Get current sandbox
        //Check for schema tab --> save content into the schema field
        if (this.state.tab === "schema") {
            Object.assign(sandbox, {
                "schema": this.ref.schema.current.getValue()
            });
        }
        //Check for readme tab --> save content into the readme field
        else if (this.state.tab === "readme") {
            Object.assign(sandbox, {
                "readme": this.ref.readme.current.getValue()
            });
        }
        //Check if sandbox is not rendered --> do not update the thumbnail
        if (this.state.rendered === false) {
            return Promise.resolve(sandbox); //Return a promise with the sandbox
        }
        //Generate the thumbnail
        let viewer =  this.ref.explore.current.viewer;
        let width = viewer.context.draw.width.value; //Get plot width
        let thumbnailWidth = 200; //Expected thumbnail width
        let scale = (width < thumbnailWidth) ? 1 : thumbnailWidth / width; //Get scale factor
        return viewer.toImageUrl("png", scale).then(function (data) {
            //console.log(data); //Thumbnail in image-url format
            return Object.assign(sandbox, {
                "thumbnail": data
            });
        });
    }
    //Render the editor page
    render() {
        let self = this;
        let state = this.state;
        return (
            <div style={{"width":"100%","height":"100%"}}>
                <SplitPanel split="vertical" resizeStyle={{"backgroundColor":"transparent"}}>
                    <SplitPanelItem primary defaultSize="50%" minSize="400px">
                        <MainPanel tab={state.tab} running={state.running} onTabChange={this.handleTabChange} onRun={this.handleRun}>
                            {/* Readme tab --> render a editor for the readme */}
                            <If condition={this.state.tab === "readme"} render={function () {
                                return React.createElement(CodeTab, {
                                    "ref": self.ref.readme,
                                    "language": "json"
                                });
                            }} />
                            {/* Schema tab --> render schema editor */}
                            <If condition={this.state.tab === "schema"} render={function () {
                                return React.createElement(CodeTab, {
                                    "ref": self.ref.schema,
                                    "language": "json"
                                });
                            }} />
                        </MainPanel>
                    </SplitPanelItem>
                    <SplitPanelItem>
                        {/* Explore panel */}
                        <Renderer render={function () {
                            return React.createElement(ExplorePanel, {
                                "ref": self.ref.explore
                            });
                        }} />
                    </SplitPanelItem>
                </SplitPanel>
            </div>
        );
    }
}

//Editor default props
SandboxEditor.defaultProps = {
    "sandbox": {}
};
<commit_msg>lab: redesigned SandboxEditor component for working with sandbox files<commit_after>import React from "react";
import {ForEach, Renderer, If} from "neutrine/lib/components";
import {SplitPanel, SplitPanelItem} from "neutrine/lib/components";

import {ExplorePanel} from "./ExplorePanel/index.js";
import {EditorPanel} from "./EditorPanel/index.js";
import {FilesPanel} from "./FilesPanel/index.js";
import {CreateFile} from "./actions/CreateFile.js";
import {createSandboxFile} from "../../utils/sandbox.js";
import {encodeSandboxFile, decodeSandboxFile} from "../../utils/sandbox.js";

//Generate a dialog to delete a file
let deleteFileDialog = function (name, cb) {
    //Display a confirmation dialog
    return window.confirm.show({
        "title": "Delete file",
        "content": `This will remove the file '${name}' from this sandbox. This action can not be undone. Continue?`,
        "onConfirm": cb,
        "confirmText": "Yes, delete",
        "cancelText": "Cancel"
    });
};

//Build state from props
let buildStateFromProps = function (props) {
    let newState = {
        //"tab": "schema", //"readme",
        "currentFile": props.sandbox.main,
        "showCreateDialog": false,
        //"sandbox": createSandbox({"name": "Untitled"}),
        "running": false,
        "rendered": false //To store if sandbox has been rendered
    };
    //Check for initial sandbox data
    //if (typeof props.sandbox === "object" && props.sandbox !== null) {
    //    newState.sandbox = Object.assign(newState.sandbox, props.sandbox);
    //}
    //Return new state
    return newState;
};

//Export sandbox editor class
export class SandboxEditor extends React.Component {
    constructor(props) {
        super(props);
        //Initialize state
        this.state = buildStateFromProps(this.props);
        //Referenced elements
        this.ref = {
            "editor": React.createRef(),
            "explore": React.createRef()
        };
        //Bind methods
        this.handleRun = this.handleRun.bind(this);
        //Bind sandbox methods
        this.getSandbox = this.getSandbox.bind(this);
        this.runSandbox = this.runSandbox.bind(this);
        //Bind dialogs methods
        this.handleCreateToggle = this.handleCreateToggle.bind(this);
        //Bind files methods
        this.handleFileCreate = this.handleFileCreate.bind(this);
        this.handleFileDelete = this.handleFileDelete.bind(this);
        this.handleFileOpen = this.handleFileOpen.bind(this);
        this.updateContent = this.updateContent.bind(this);
        //this.forceFileChange = this.forceFileChange.bind(this);
    }
    //Component dod mount --> set tab content
    componentDidMount() {
        return this.updateContent();
    }
    //Component did update --> update tab content
    componentDidUpdate() {
        //return this.updateContent();
    }
    //Handle run click
    handleRun() {
        return this.runSandbox();
    }
    //Handle file create dialog toggle
    handleCreateToggle() {
        return this.setState({
            "showCreateDialog": !this.state.showCreateDialog
        });
    }
    //Handle file create submit --> create the new file
    handleFileCreate(file) {
        let self = this;
        //Get the current sandbox data and add the new file
        return this.getSandbox().then(function (sandbox) {
            sandbox.files[file.name] = createSandboxFile(file.type, "");
            //Update the sandbox and open the new file
            return self.props.onChange(sandbox, function () {
                let newState = {
                    "showCreateDialog": false,
                    "currentFile": file.name
                };
                return self.setState(newState, function () {
                    return self.updateContent();
                });
            });
        });
    }
    //Handle file delete --> show dialog to delete the file
    handleFileDelete(file) {
        let self = this;
        return deleteFileDialog(file, function () {
            return self.getSandbox().then(function (sandbox) {
                //Delete the file from this sandbox
                delete sandbox.files[file];
                //Update the sandbox and open the new file
                return self.props.onChange(sandbox, function () {
                    //Check if the current file is not the removed file
                    if (file !== self.state.currentFile) {
                        return null; //Nothing to do
                    }
                    //Change the current file --> display the first one instead
                    //let newFile = Object.keys(sandbox.files)[0];
                    return self.setState({"currentFile": sandbox.main}, function () {
                        return self.updateContent();
                    });
                });
            });
        });
    }
    //Handle file open --> save content and open this file
    handleFileOpen(newFile) {
        let self = this;
        //Check if we are trying to open the current file
        if (this.state.currentFile === newFile) {
            return null;
        }
        //Update the sandbox before opening the file
        return this.getSandbox().then(function (sandbox) {
            return self.props.onChange(sandbox, function () {
                return self.setState({"currentFile": newFile}, function () {
                    return self.updateContent();
                });
            });
        });
    }
    //Update content
    updateContent() {
        let name = this.state.currentFile; //Get current file name
        let sandbox = this.props.sandbox; //Get sandbox
        //Check for schema tab --> set schema value
        //if (this.state.tab === "schema") {
        //    this.ref.editor.current.setValue(sandbox.schema);
        //}
        ////Check for readme tab --> set readme value
        //else if (this.state.tab === "readme" && typeof sandbox.readme === "string") {
        //    this.ref.readme.current.setValue(sandbox.readme);
        //}
        //Update file content
        let content = sandbox.files[name].content; //Get current content
        this.ref.editor.current.setValue(decodeSandboxFile(content));
    }
    //Run sandbox
    runSandbox(cb) {
        let self = this;
        let rendered = false;
        //let sandbox = this.getSandbox(); //Get current sandbox state
        //Update the state before running the sandbox
        return this.setState({"running": true}, function () {
            return self.getSandbox().then(function (sandbox) {
                return self.ref.explore.current.run(sandbox, self.state.currentFile);
            }).then(function() {
                rendered = true; //Plot rendered
            }).catch(function (error) {
                //Something went wrong rendering the plot
                //console.error(error);
            }).finally(function () {
                //In both cases, running process has been finished
                return self.setState({
                    "running": false,
                    "rendered": rendered
                });
            });
        });
    }
    //Get the current state of the sandbox
    getSandbox() {
        let self = this;
        let currentFile = this.state.currentFile; //Get current file
        let sandbox = Object.assign({}, this.props.sandbox); //Get current sandbox
        //Check for schema tab --> save content into the schema field
        //if (this.state.tab === "schema") {
        //    Object.assign(sandbox, {
        //        "schema": this.ref.editor.current.getValue()
        //    });
        //}
        ////Check for readme tab --> save content into the readme field
        //else if (this.state.tab === "readme") {
        //    Object.assign(sandbox, {
        //        "readme": this.ref.readme.current.getValue()
        //    });
        //}
        //Save the current file content
        sandbox.files[currentFile].content = encodeSandboxFile(this.ref.editor.current.getValue());
        //Check if sandbox is not rendered --> do not update the thumbnail
        if (this.state.rendered === false) {
            return Promise.resolve(sandbox); //Return a promise with the sandbox
        }
        //Generate the thumbnail
        let viewer =  this.ref.explore.current.viewer;
        let width = viewer.context.draw.width.value; //Get plot width
        let thumbnailWidth = 200; //Expected thumbnail width
        let scale = (width < thumbnailWidth) ? 1 : thumbnailWidth / width; //Get scale factor
        return viewer.toImageUrl("png", scale).then(function (data) {
            //console.log(data); //Thumbnail in image-url format
            return Object.assign(sandbox, {
                "thumbnail": data
            });
        });
    }
    //Render the editor page
    render() {
        let self = this;
        let state = this.state;
        let sandbox = this.props.sandbox; //Get current sandbox state
        return (
            <div className="siimple--flex" style={{"width":"100%","height":"100%"}}>
                <Renderer render={function () {
                    return React.createElement(FilesPanel, {
                        "sandbox": self.props.sandbox,
                        "visible": self.props.showFilesPanel,
                        "currentFile": self.state.currentFile,
                        "onFileClick": self.handleFileOpen,
                        "onFileDelete": self.handleFileDelete,
                        "onCreate": self.handleCreateToggle
                    });
                }} />
                <SplitPanel split="vertical" resizeStyle={{"backgroundColor":"transparent"}}>
                    <SplitPanelItem primary defaultSize="50%" minSize="400px">
                        <Renderer render={function () {
                            let filename = self.state.currentFile;
                            let filetype = (typeof sandbox.files[filename] !== "undefined") ? sandbox.files[filename].type : "";
                            return React.createElement(EditorPanel, {
                                "ref": self.ref.editor,
                                "filename": filename,
                                "filetype": filetype,
                                "running": self.state.running,
                                "onRun": self.handleRun
                            });
                        }} />
                    </SplitPanelItem>
                    <SplitPanelItem>
                        {/* Explore panel */}
                        <Renderer render={function () {
                            return React.createElement(ExplorePanel, {
                                "ref": self.ref.explore
                            });
                        }} />
                    </SplitPanelItem>
                </SplitPanel>
                {/* Create a new file dialog */}
                <If condition={this.state.showCreateDialog} render={function () {
                    return React.createElement(CreateFile, {
                        "onClose": self.handleCreateToggle,
                        "onSubmit": self.handleFileCreate,
                        "sandbox": self.props.sandbox
                    });
                }} />
            </div>
        );
    }
}

//Editor default props
SandboxEditor.defaultProps = {
    "sandbox": {},
    "showFilesPanel": true
};

{'fraction_non_alphanumeric': 0.12030075187969924, 'fraction_numerical': 0.0016530688423185623, 'mean_word_length': 1.6280829596412556, 'pattern_counts': {'":': 70, '<': 30, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2999897', 'n_tokens_mistral': 4904, 'n_tokens_neox': 4673, 'n_words': 1214}