custom script runner UI

pull/5323/head
bunsenstraat 2 months ago
parent eced8cd546
commit 9bf9b3ebe5
  1. 37
      apps/remix-ide/src/app/tabs/script-runner-ui.tsx
  2. 1
      libs/remix-ui/scriptrunner/src/index.ts
  3. 159
      libs/remix-ui/scriptrunner/src/lib/custom-script-runner.tsx
  4. 47
      libs/remix-ui/scriptrunner/src/lib/script-runner-ui.tsx
  5. 5
      libs/remix-ui/scriptrunner/src/types/index.ts

@ -1,9 +1,10 @@
import { IframePlugin, IframeProfile, ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line
import { ScriptRunnerUI } from '@remix-scriptrunner' // eslint-disable-line
import { customScriptRunnerConfig, Dependency, ScriptRunnerUI } from '@remix-scriptrunner' // eslint-disable-line
import { Profile } from '@remixproject/plugin-utils'
import { Engine } from '@remixproject/engine'
import axios from 'axios'
const profile = {
name: 'scriptRunnerBridge',
@ -98,10 +99,42 @@ export class ScriptRunnerUIPlugin extends ViewPlugin {
this.emit('info', data)
}
async buildScriptRunner(dependencies: Dependency[]) {
console.log('buildScriptRunner', dependencies)
}
async loadCustomConfig(){
console.log('loadCustomConfig')
await this.call('fileManager', 'open', 'script.config.json')
const content = await this.call('fileManager', 'readFile', 'script.config.json')
return JSON.parse(content)
}
async saveCustomConfig(content: customScriptRunnerConfig){
console.log('saveCustomConfig', content)
await this.call('fileManager', 'writeFile', 'script.config.json', JSON.stringify(content, null, 2))
}
async activateCustomScriptRunner(config: customScriptRunnerConfig){
console.log('activateCustomScriptRunner', config)
// post config to localhost:4000 using axios
const result = await axios.post('http://localhost:4000/build', config)
console.log(result)
if(result.data.hash) {
await this.loadScriptRunner(result.data.hash)
}
return result.data.hash
}
render() {
return (
<div id="scriptRunnerTab">
<ScriptRunnerUI loadScriptRunner={this.loadScriptRunner.bind(this)} />
<ScriptRunnerUI
activateCustomScriptRunner={this.activateCustomScriptRunner.bind(this)}
saveCustomConfig={this.saveCustomConfig.bind(this)}
loadCustomConfig={this.loadCustomConfig.bind(this)}
buildScriptRunner={this.buildScriptRunner.bind(this)}
loadScriptRunner={this.loadScriptRunner.bind(this)} />
</div>
)
}

@ -1 +1,2 @@
export { ScriptRunnerUI } from './lib/script-runner-ui';
export * from './types';

@ -0,0 +1,159 @@
import React, { useEffect, useState } from "react";
import { Accordion, Card, Button } from "react-bootstrap";
import axios from "axios";
import { customScriptRunnerConfig, Dependency, ProjectConfiguration } from "../types";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTrash } from "@fortawesome/free-solid-svg-icons";
export interface ScriptRunnerUIProps {
// build custom script runner
buildScriptRunner: (dependencies: Dependency[]) => void;
publishedConfigurations: ProjectConfiguration[];
loadCustomConfig: () => any;
saveCustomConfig(content: customScriptRunnerConfig): void;
activateCustomScriptRunner(config: customScriptRunnerConfig): string;
addCustomConfig(config: ProjectConfiguration) : void;
}
export const CustomScriptRunner = (props: ScriptRunnerUIProps) => {
const [dependencies, setDependencies] = useState<Dependency[]>([]);
const [name, setName] = useState<string>('');
const [alias, setAlias] = useState<string>('');
const [version, setVersion] = useState<string>('');
const [baseConfig, setBaseConfig] = useState<string>('default');
const [loading, setLoading] = useState<boolean>(false);
const handleAddDependency = () => {
if (name.trim() && version.trim()) {
const newDependency: Dependency = { name, version, import: true, alias };
setDependencies([...dependencies, newDependency]);
setName('');
setVersion('');
} else {
alert('Please fill out both name and version.');
}
};
const handleRemoveDependency = (index: number) => {
const updatedDependencies = dependencies.filter((_, i) => i !== index);
setDependencies(updatedDependencies);
};
const handleSaveToFile = () => {
const fileData = JSON.stringify(dependencies, null, 2);
console.log(fileData, baseConfig);
const customConfig: customScriptRunnerConfig = { baseConfiguration: baseConfig, dependencies };
console.log(customConfig);
props.saveCustomConfig(customConfig);
};
const loadFromFile = async () => {
const fileData: customScriptRunnerConfig = await props.loadCustomConfig();
console.log(fileData);
setDependencies(fileData.dependencies);
setBaseConfig(fileData.baseConfiguration);
}
const activateCustomConfig = async () => {
console.log('activate');
const customConfig: customScriptRunnerConfig = { baseConfiguration: baseConfig, dependencies };
console.log(customConfig);
setLoading(true);
const loadedConfig = await props.activateCustomScriptRunner(customConfig);
console.log(loadedConfig);
const newConfig: ProjectConfiguration = {
name: loadedConfig,
publish: true,
description: `Extension of ${baseConfig}`,
dependencies: dependencies,
replacements: {}
};
console.log(newConfig);
props.addCustomConfig(newConfig);
setLoading(false);
}
const onSelectBaseConfig = (e: React.ChangeEvent<HTMLSelectElement>) => {
setBaseConfig(e.target.value);
}
if (loading) {
return <div style={{ padding: '20px', maxWidth: '400px', margin: 'auto' }}>
<div className="text-center py-5">
<i className="fas fa-spinner fa-pulse fa-2x"></i>
</div>
</div>
}
return (
<div style={{ padding: '20px', maxWidth: '400px', margin: 'auto' }}>
<h5>Custom configuration</h5>
<label>Select a base configuration</label>
<select value={baseConfig} className="form-control" onChange={onSelectBaseConfig} style={{ marginBottom: '10px' }}>
<option value="none">Select a base configuration</option>
{props.publishedConfigurations.map((config: ProjectConfiguration, index) => (
<option key={index} value={config.name}>
{config.name}
</option>
))}
</select>
<label>Add dependencies</label>
<div style={{ marginBottom: '10px' }}>
<input
type="text"
placeholder="Dependency Name"
value={name}
className="form-control"
onChange={(e) => setName(e.target.value)}
style={{ marginRight: '10px' }}
/>
<input
type="text"
placeholder="Alias"
className="form-control mt-1"
value={alias}
onChange={(e) => setAlias(e.target.value)} />
<input
type="text"
placeholder="Version"
className="form-control mt-1"
value={version}
onChange={(e) => setVersion(e.target.value)}
/>
<button
className="btn btn-primary w-100 mt-1"
onClick={handleAddDependency}>
Add
</button>
</div>
<ul>
{dependencies.map((dependency, index) => (
<li key={index} style={{ marginBottom: '5px' }}>
<div className="d-flex align-items-baseline justify-content-between">
{dependency.name} - {dependency.version}
<button
onClick={() => handleRemoveDependency(index)}
className="btn btn-danger"
style={{ marginLeft: '10px' }}
>
<FontAwesomeIcon icon={faTrash} />
</button>
</div>
</li>
))}
</ul>
{dependencies.length > 0 && (
<button className="btn btn-primary w-100" onClick={handleSaveToFile} style={{ marginTop: '20px' }}>
Save List to File
</button>
)}
<button className="btn btn-primary w-100" onClick={loadFromFile} style={{ marginTop: '20px' }}>
Load from File
</button>
{dependencies.length > 0 && (
<button className="btn btn-success w-100" onClick={activateCustomConfig} style={{ marginTop: '20px' }}>
Activate
</button>)}
</div>
);
}

@ -1,22 +1,28 @@
import React, { useEffect, useState } from "react";
import { Accordion, Card, Button } from "react-bootstrap";
import axios from "axios";
import { ProjectConfiguration } from "./types";
import { customScriptRunnerConfig, Dependency, ProjectConfiguration } from "../types";
import { FormattedMessage } from "react-intl";
import { faCheck, faToggleOn } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Profile } from "@remixproject/plugin-utils";
import { IframeProfile, ViewProfile } from "@remixproject/engine-web";
import { Plugin } from "@remixproject/engine";
import { CustomScriptRunner } from "./custom-script-runner";
export interface ScriptRunnerUIProps {
// Add your props here
loadScriptRunner: (name: string) => void;
// build custom script runner
buildScriptRunner: (dependencies: Dependency[]) => void;
loadCustomConfig: () => any;
saveCustomConfig(content: customScriptRunnerConfig): void;
activateCustomScriptRunner(config: customScriptRunnerConfig): string;
}
export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => {
const { loadScriptRunner } = props;
const [configurations, setConfigurations] = useState([]);
const [configurations, setConfigurations] = useState<ProjectConfiguration[]>([]);
const [activeKey, setActiveKey] = useState('default');
const [activeConfig, setActiveConfig] = useState('default');
@ -41,23 +47,34 @@ export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => {
loadScriptRunner(key)
};
// Filter out unpublished configurations
const publishedConfigurations = configurations.filter((config) => config.publish);
const addCustomConfig = (config: ProjectConfiguration) => {
if(configurations.find((c) => c.name === config.name)) {
return;
}
setConfigurations([...configurations, config]);
setActiveConfig(config.name);
}
return (
<div className="px-1">
<Accordion defaultActiveKey="default">
{publishedConfigurations.map((config: ProjectConfiguration, index) => (
{configurations.filter((config) => config.publish).map((config: ProjectConfiguration, index) => (
<div key={index}>
<div className="d-flex align-items-baseline justify-content-between">
<Accordion.Toggle as={Button} variant="link" eventKey={config.name}>
<span className="pl-2">{config.name}</span>
<Accordion.Toggle as={Button} variant="link" eventKey={config.name}
style={{
overflowX: 'hidden',
textOverflow: 'ellipsis'
}}
>
<div className="pl-2">{config.name}</div>
</Accordion.Toggle>
<div onClick={() => handleSelect(config.name)} className="pointer px-2">
{activeConfig !== config.name ?
<FontAwesomeIcon icon={faToggleOn}></FontAwesomeIcon> :
<FontAwesomeIcon className="text-success" icon={faCheck}></FontAwesomeIcon>
}
{activeConfig !== config.name ?
<FontAwesomeIcon icon={faToggleOn}></FontAwesomeIcon> :
<FontAwesomeIcon className="text-success" icon={faCheck}></FontAwesomeIcon>
}
</div>
</div>
@ -75,7 +92,13 @@ export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => {
</ul></>
</Accordion.Collapse></div>))}
</Accordion>
<CustomScriptRunner
addCustomConfig={addCustomConfig}
activateCustomScriptRunner={props.activateCustomScriptRunner}
saveCustomConfig={props.saveCustomConfig}
loadCustomConfig={props.loadCustomConfig}
publishedConfigurations={configurations.filter((config) => config.publish)}
buildScriptRunner={props.buildScriptRunner} />
</div>
);
};

@ -18,3 +18,8 @@ export interface Dependency {
dependencies: Dependency[];
replacements: Replacements;
}
export interface customScriptRunnerConfig {
baseConfiguration: string;
dependencies: Dependency[];
}
Loading…
Cancel
Save