seperate plugins

pull/5652/head
bunsenstraat 1 month ago
parent dfe1a2cb43
commit 25af64043a
  1. 9
      apps/remix-ide/src/app.ts
  2. 361
      apps/remix-ide/src/app/plugins/script-runner-bridge.tsx
  3. 373
      apps/remix-ide/src/app/tabs/script-runner-ui.tsx
  4. 2
      libs/remix-ui/scriptrunner/src/lib/script-runner-ui.tsx
  5. 8
      libs/remix-ui/scriptrunner/src/types/index.ts
  6. 2
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx

@ -78,7 +78,7 @@ import * as remixLib from '@remix-project/remix-lib'
import { QueryParams } from '@remix-project/remix-lib'
import { SearchPlugin } from './app/tabs/search'
import { ScriptRunnerUIPlugin } from './app/tabs/script-runner-ui'
import { ScriptRunnerBridgePlugin } from './app/plugins/script-runner-bridge'
import { ElectronProvider } from './app/files/electronProvider'
const Storage = remixLib.Storage
@ -103,6 +103,7 @@ import Filepanel from './app/panels/file-panel'
import Editor from './app/editor/editor'
import Terminal from './app/panels/terminal'
import TabProxy from './app/panels/tab-proxy.js'
import { any } from 'async'
const _paq = (window._paq = window._paq || [])
@ -281,7 +282,7 @@ class AppComponent {
const search = new SearchPlugin()
//---------------- Script Runner UI Plugin -------------------------
const scriptRunnerUI = new ScriptRunnerUIPlugin(this.engine)
const scriptRunnerUI = new ScriptRunnerBridgePlugin(this.engine)
//---- templates
const templates = new TemplatesPlugin()
@ -677,7 +678,9 @@ class AppComponent {
this.appManager.call('sidePanel', 'pinView', JSON.parse(lastPinned))
}
})
.catch(console.error)
.catch((e) => {
console.error(e)
})
}
const loadedElement = document.createElement('span')
loadedElement.setAttribute('data-id', 'apploaded')

@ -0,0 +1,361 @@
import { IframePlugin, IframeProfile, ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line
import { customScriptRunnerConfig, IScriptRunnerState, ProjectConfiguration, ScriptRunnerConfig, ScriptRunnerUI } from '@remix-scriptrunner'
import { Profile } from '@remixproject/plugin-utils'
import { Engine, Plugin } from '@remixproject/engine'
import axios from 'axios'
import { AppModal } from '@remix-ui/app'
import { isArray } from 'lodash'
import { PluginViewWrapper } from '@remix-ui/helper'
import { CustomRemixApi } from '@remix-api'
import { ScriptRunnerUIPlugin } from '../tabs/script-runner-ui'
const profile = {
name: 'scriptRunnerBridge',
displayName: 'Script configuration',
methods: ['execute'],
events: ['log', 'info', 'warn', 'error'],
icon: 'assets/img/solid-gear-circle-play.svg',
description: 'Configure the dependencies for running scripts.',
kind: '',
version: packageJson.version,
maintainedBy: 'Remix',
}
const configFileName = '.remix/script.config.json'
let baseUrl = 'https://remix-project-org.github.io/script-runner-generator'
const customBuildUrl = 'http://localhost:4000/build' // this will be used when the server is ready
export class ScriptRunnerBridgePlugin extends Plugin {
engine: Engine
dispatch: React.Dispatch<any> = () => {}
workspaceScriptRunnerDefaults: Record<string, string>
customConfig: ScriptRunnerConfig
configurations: ProjectConfiguration[]
activeConfig: ProjectConfiguration
enableCustomScriptRunner: boolean
plugin: Plugin<any, CustomRemixApi>
scriptRunnerProfileName: string
initialized: boolean = false
constructor(engine: Engine) {
super(profile)
this.engine = engine
this.workspaceScriptRunnerDefaults = {}
this.plugin = this
this.enableCustomScriptRunner = false // implement this later
}
async onActivation() {
if(!this.initialized) {
this.setListeners()
await this.init()
this.initialized = true
}
this.renderComponent()
}
async init() {
await this.loadCustomConfig()
await this.loadConfigurations()
const ui: ScriptRunnerUIPlugin = new ScriptRunnerUIPlugin(this)
this.engine.register(ui)
}
setListeners() {
this.on('filePanel', 'setWorkspace', async (workspace: string) => {
this.activeConfig = null
this.customConfig = {
defaultConfig: 'default',
customConfig: {
baseConfiguration: 'default',
dependencies: [],
},
}
await this.loadCustomConfig()
await this.loadConfigurations()
this.renderComponent()
})
this.plugin.on('fileManager', 'fileSaved', async (file: string) => {
if (file === configFileName && this.enableCustomScriptRunner) {
await this.loadCustomConfig()
this.renderComponent()
}
})
}
async renderComponent() {
this.emit('render')
}
async selectScriptRunner(config: ProjectConfiguration) {
if (await this.loadScriptRunner(config)) await this.saveCustomConfig(this.customConfig)
}
async loadScriptRunner(config: ProjectConfiguration): Promise<boolean> {
const profile: Profile = await this.plugin.call('manager', 'getProfile', 'scriptRunner')
this.scriptRunnerProfileName = profile.name
const testPluginName = localStorage.getItem('test-plugin-name')
const testPluginUrl = localStorage.getItem('test-plugin-url')
let url = `${baseUrl}?template=${config.name}&timestamp=${Date.now()}`
if (testPluginName === 'scriptRunner') {
// if testpluginurl has template specified only use that
if (testPluginUrl.indexOf('template') > -1) {
url = testPluginUrl
} else {
baseUrl = `//${new URL(testPluginUrl).host}`
url = `${baseUrl}?template=${config.name}&timestamp=${Date.now()}`
}
}
//console.log('loadScriptRunner', profile)
const newProfile: IframeProfile = {
...profile,
name: profile.name + config.name,
location: 'hiddenPanel',
url: url,
}
let result = null
try {
this.setIsLoading(config.name, true)
const plugin: IframePlugin = new IframePlugin(newProfile)
if (!this.engine.isRegistered(newProfile.name)) {
await this.engine.register(plugin)
}
await this.plugin.call('manager', 'activatePlugin', newProfile.name)
this.activeConfig = config
this.on(newProfile.name, 'log', this.log.bind(this))
this.on(newProfile.name, 'info', this.info.bind(this))
this.on(newProfile.name, 'warn', this.warn.bind(this))
this.on(newProfile.name, 'error', this.error.bind(this))
this.on(newProfile.name, 'dependencyError', this.dependencyError.bind(this))
this.customConfig.defaultConfig = config.name
this.setErrorStatus(config.name, false, '')
result = true
} catch (e) {
console.log('Error loading script runner: ', newProfile.name, e)
const iframe = document.getElementById(`plugin-${newProfile.name}`)
if (iframe) {
await this.call('hiddenPanel', 'removeView', newProfile)
}
delete (this.engine as any).manager.profiles[newProfile.name]
delete (this.engine as any).plugins[newProfile.name]
console.log('Error loading script runner: ', newProfile.name, e)
this.setErrorStatus(config.name, true, e)
result = false
}
this.setIsLoading(config.name, false)
this.renderComponent()
return result
}
async execute(script: string, filePath: string) {
this.call('terminal', 'log', { value: `running ${filePath} ...`, type: 'info' })
if (!this.scriptRunnerProfileName || !this.engine.isRegistered(`${this.scriptRunnerProfileName}${this.activeConfig.name}`)) {
console.error('Script runner not loaded')
if (!(await this.loadScriptRunner(this.activeConfig))) {
console.error('Error loading script runner')
return
}
}
try {
this.setIsLoading(this.activeConfig.name, true)
await this.call(`${this.scriptRunnerProfileName}${this.activeConfig.name}`, 'execute', script, filePath)
} catch (e) {
console.error('Error executing script', e)
}
this.setIsLoading(this.activeConfig.name, false)
}
async setErrorStatus(name: string, status: boolean, error: string) {
this.configurations.forEach((config) => {
if (config.name === name) {
config.errorStatus = status
config.error = error
}
})
this.renderComponent()
}
async setIsLoading(name: string, status: boolean) {
if (status) {
this.emit('statusChanged', {
key: 'loading',
type: 'info',
title: 'loading...',
})
} else {
this.emit('statusChanged', {
key: 'none',
})
}
this.configurations.forEach((config) => {
if (config.name === name) {
config.isLoading = status
}
})
this.renderComponent()
}
async dependencyError(data: any) {
console.log('Script runner dependency error: ', data)
let message = `Error loading dependencies: `
if (isArray(data.data)) {
data.data.forEach((data: any) => {
message += `${data}`
})
}
const modal: AppModal = {
id: 'TemplatesSelection',
title: 'Missing dependencies',
message: `${message} \n\n You may need to setup a script engine for this workspace to load the correct dependencies. Do you want go to setup now?`,
okLabel: window._intl.formatMessage({ id: 'filePanel.ok' }),
cancelLabel: 'ignore',
}
const modalResult = await this.plugin.call('notification' as any, 'modal', modal)
if (modalResult) {
// await this.plugin.call('menuicons', 'select', 'scriptRunnerBridge')
} else {
}
}
async log(data: any) {
this.emit('log', data)
}
async warn(data: any) {
this.emit('warn', data)
}
async error(data: any) {
this.emit('error', data)
}
async info(data: any) {
this.emit('info', data)
}
async loadCustomConfig(): Promise<void> {
try {
const content = await this.plugin.call('fileManager', 'readFile', configFileName)
const parsed = JSON.parse(content)
this.customConfig = parsed
} catch (e) {
this.customConfig = {
defaultConfig: 'default',
customConfig: {
baseConfiguration: 'default',
dependencies: [],
},
}
}
}
async openCustomConfig() {
try {
await this.plugin.call('fileManager', 'open', '.remix/script.config.json')
} catch (e) {}
}
async loadConfigurations() {
try {
const response = await axios.get(`${baseUrl}/projects.json?timestamp=${Date.now()}`)
this.configurations = response.data
// find the default otherwise pick the first one as the active
this.configurations.forEach((config) => {
if (config.name === this.customConfig.defaultConfig) {
this.activeConfig = config
}
})
if (!this.activeConfig) {
this.activeConfig = this.configurations[0]
}
} catch (error) {
console.error('Error fetching the projects data:', error)
}
}
async saveCustomConfig(content: ScriptRunnerConfig) {
if (content.customConfig.dependencies.length === 0 && content.defaultConfig === 'default') {
try {
const exists = await this.plugin.call('fileManager', 'exists', '.remix/script.config.json')
if (exists) {
await this.plugin.call('fileManager', 'remove', '.remix/script.config.json')
}
} catch (e) {}
return
}
await this.plugin.call('fileManager', 'writeFile', '.remix/script.config.json', JSON.stringify(content, null, 2))
}
async activateCustomScriptRunner(config: customScriptRunnerConfig) {
try {
const result = await axios.post(customBuildUrl, config)
if (result.data.hash) {
const newConfig: ProjectConfiguration = {
name: result.data.hash,
title: 'Custom configuration',
publish: true,
description: `Extension of ${config.baseConfiguration}`,
dependencies: config.dependencies,
replacements: {},
errorStatus: false,
error: '',
isLoading: false,
}
this.configurations.push(newConfig)
this.renderComponent()
await this.loadScriptRunner(result.data.hash)
}
return result.data.hash
} catch (error) {
let message
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log('Error status:', error.response.status)
console.log('Error data:', error.response.data) // This should give you the output being sent
console.log('Error headers:', error.response.headers)
if (error.response.data.error) {
if (isArray(error.response.data.error)) {
const message = `${error.response.data.error[0]}`
this.plugin.call('notification', 'alert', {
id: 'scriptalert',
message,
title: 'Error',
})
throw new Error(message)
}
message = `${error.response.data.error}`
}
message = `Uknown error: ${error.response.data}`
this.plugin.call('notification', 'alert', {
id: 'scriptalert',
message,
title: 'Error',
})
throw new Error(message)
} else if (error.request) {
// The request was made but no response was received
console.log('No response received:', error.request)
throw new Error('No response received')
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error message:', error.message)
throw new Error(error.message)
}
}
}
}

@ -1,7 +1,7 @@
import { IframePlugin, IframeProfile, ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line
import { customScriptRunnerConfig, ProjectConfiguration, ScriptRunnerConfig, ScriptRunnerUI } from '@remix-scriptrunner' // eslint-disable-line
import { customScriptRunnerConfig, IScriptRunnerState, ProjectConfiguration, ScriptRunnerConfig, ScriptRunnerUI } from '@remix-scriptrunner'
import { Profile } from '@remixproject/plugin-utils'
import { Engine, Plugin } from '@remixproject/engine'
import axios from 'axios'
@ -9,76 +9,34 @@ import { AppModal } from '@remix-ui/app'
import { isArray } from 'lodash'
import { PluginViewWrapper } from '@remix-ui/helper'
import { CustomRemixApi } from '@remix-api'
import { ScriptRunnerBridgePlugin } from '../plugins/script-runner-bridge'
const profile = {
name: 'scriptRunnerBridge',
name: 'UIScriptRunner',
displayName: 'Script configuration',
methods: ['execute'],
events: ['log', 'info', 'warn', 'error'],
methods: [],
events: [],
icon: 'assets/img/solid-gear-circle-play.svg',
description: 'Configure the dependencies for running scripts.',
kind: '',
location: 'sidePanel',
location: 'mainPanel',
version: packageJson.version,
maintainedBy: 'Remix'
}
const configFileName = '.remix/script.config.json'
let baseUrl = 'https://remix-project-org.github.io/script-runner-generator'
const customBuildUrl = 'http://localhost:4000/build' // this will be used when the server is ready
interface IScriptRunnerState {
customConfig: customScriptRunnerConfig
configurations: ProjectConfiguration[]
activeConfig: ProjectConfiguration
enableCustomScriptRunner: boolean
maintainedBy: 'Remix',
}
export class ScriptRunnerUIPlugin extends ViewPlugin {
engine: Engine
dispatch: React.Dispatch<any> = () => { }
workspaceScriptRunnerDefaults: Record<string, string>
customConfig: ScriptRunnerConfig
configurations: ProjectConfiguration[]
activeConfig: ProjectConfiguration
enableCustomScriptRunner: boolean
plugin: Plugin<any, CustomRemixApi>
scriptRunnerProfileName: string
constructor(engine: Engine) {
dispatch: React.Dispatch<IScriptRunnerState> = () => {}
state: IScriptRunnerState
bridge: ScriptRunnerBridgePlugin
constructor(plugin: ScriptRunnerBridgePlugin) {
super(profile)
this.engine = engine
this.workspaceScriptRunnerDefaults = {}
this.plugin = this
this.enableCustomScriptRunner = false // implement this later
this.bridge = plugin
}
async onActivation() {
this.on('filePanel', 'setWorkspace', async (workspace: string) => {
this.activeConfig = null
this.customConfig =
{
defaultConfig: 'default',
customConfig: {
baseConfiguration: 'default',
dependencies: []
}
}
await this.loadCustomConfig()
await this.loadConfigurations()
this.on('scriptRunnerBridge', 'render', () => {
this.renderComponent()
})
this.plugin.on('fileManager', 'fileSaved', async (file: string) => {
if (file === configFileName && this.enableCustomScriptRunner) {
await this.loadCustomConfig()
this.renderComponent()
}
})
await this.loadCustomConfig()
await this.loadConfigurations()
})
this.renderComponent()
}
@ -90,310 +48,37 @@ export class ScriptRunnerUIPlugin extends ViewPlugin {
)
}
setDispatch(dispatch: React.Dispatch<any>) {
setDispatch(dispatch: React.Dispatch<IScriptRunnerState>) {
this.dispatch = dispatch
this.renderComponent()
}
renderComponent() {
this.dispatch({
customConfig: this.customConfig,
configurations: this.configurations,
activeConfig: this.activeConfig,
enableCustomScriptRunner: this.enableCustomScriptRunner
})
}
updateComponent(state: IScriptRunnerState) {
return (
<ScriptRunnerUI
customConfig={state.customConfig}
configurations={state.configurations}
activeConfig={state.activeConfig}
enableCustomScriptRunner={state.enableCustomScriptRunner}
activateCustomScriptRunner={this.activateCustomScriptRunner.bind(this)}
saveCustomConfig={this.saveCustomConfig.bind(this)}
openCustomConfig={this.openCustomConfig.bind(this)}
loadScriptRunner={this.selectScriptRunner.bind(this)} />
)
}
async selectScriptRunner(config: ProjectConfiguration) {
if (await this.loadScriptRunner(config))
await this.saveCustomConfig(this.customConfig)
}
async loadScriptRunner(config: ProjectConfiguration): Promise<boolean> {
const profile: Profile = await this.plugin.call('manager', 'getProfile', 'scriptRunner')
this.scriptRunnerProfileName = profile.name
const testPluginName = localStorage.getItem('test-plugin-name')
const testPluginUrl = localStorage.getItem('test-plugin-url')
let url = `${baseUrl}?template=${config.name}&timestamp=${Date.now()}`
if (testPluginName === 'scriptRunner') {
// if testpluginurl has template specified only use that
if (testPluginUrl.indexOf('template') > -1) {
url = testPluginUrl
} else {
baseUrl = `//${new URL(testPluginUrl).host}`
url = `${baseUrl}?template=${config.name}&timestamp=${Date.now()}`
}
}
//console.log('loadScriptRunner', profile)
const newProfile: IframeProfile = {
...profile,
name: profile.name + config.name,
location: 'hiddenPanel',
url: url
}
let result = null
try {
this.setIsLoading(config.name, true)
const plugin: IframePlugin = new IframePlugin(newProfile)
if (!this.engine.isRegistered(newProfile.name)) {
await this.engine.register(plugin)
}
await this.plugin.call('manager', 'activatePlugin', newProfile.name)
this.activeConfig = config
this.on(newProfile.name, 'log', this.log.bind(this))
this.on(newProfile.name, 'info', this.info.bind(this))
this.on(newProfile.name, 'warn', this.warn.bind(this))
this.on(newProfile.name, 'error', this.error.bind(this))
this.on(newProfile.name, 'dependencyError', this.dependencyError.bind(this))
this.customConfig.defaultConfig = config.name
this.setErrorStatus(config.name, false, '')
result = true
} catch (e) {
console.log('Error loading script runner: ', newProfile.name, e)
const iframe = document.getElementById(`plugin-${newProfile.name}`);
if (iframe) {
await this.call('hiddenPanel', 'removeView', newProfile)
}
delete (this.engine as any).manager.profiles[newProfile.name]
delete (this.engine as any).plugins[newProfile.name]
console.log('Error loading script runner: ', newProfile.name, e)
this.setErrorStatus(config.name, true, e)
result = false
}
this.setIsLoading(config.name, false)
this.renderComponent()
return result
}
async execute(script: string, filePath: string) {
this.call('terminal', 'log', { value: `running ${filePath} ...`, type: 'info' })
if (!this.scriptRunnerProfileName || !this.engine.isRegistered(`${this.scriptRunnerProfileName}${this.activeConfig.name}`)) {
if (!await this.loadScriptRunner(this.activeConfig)) {
console.error('Error loading script runner')
return
}
}
try {
this.setIsLoading(this.activeConfig.name, true)
await this.call(`${this.scriptRunnerProfileName}${this.activeConfig.name}`, 'execute', script, filePath)
} catch (e) {
console.error('Error executing script', e)
}
this.setIsLoading(this.activeConfig.name, false)
}
async setErrorStatus(name: string, status: boolean, error: string) {
this.configurations.forEach((config) => {
if (config.name === name) {
config.errorStatus = status
config.error = error
}
customConfig: this.bridge.customConfig.customConfig,
configurations: this.bridge.configurations,
activeConfig: this.bridge.activeConfig,
enableCustomScriptRunner: this.bridge.enableCustomScriptRunner,
})
this.renderComponent()
}
async setIsLoading(name: string, status: boolean) {
if (status) {
this.emit('statusChanged', {
key: 'loading',
type: 'info',
title: 'loading...'
})
} else {
this.emit('statusChanged', {
key: 'none'
})
}
this.configurations.forEach((config) => {
if (config.name === name) {
config.isLoading = status
}
})
this.renderComponent()
}
async dependencyError(data: any) {
console.log('Script runner dependency error: ', data)
let message = `Error loading dependencies: `
if (isArray(data.data)) {
data.data.forEach((data: any) => {
message += `${data}`
})
}
const modal: AppModal = {
id: 'TemplatesSelection',
title: 'Missing dependencies',
message: `${message} \n\n You may need to setup a script engine for this workspace to load the correct dependencies. Do you want go to setup now?`,
okLabel: window._intl.formatMessage({ id: 'filePanel.ok' }),
cancelLabel: 'ignore'
}
const modalResult = await this.plugin.call('notification' as any, 'modal', modal)
if (modalResult) {
await this.plugin.call('menuicons', 'select', 'scriptRunnerBridge')
} else {
}
}
async log(data: any) {
this.emit('log', data)
}
async warn(data: any) {
this.emit('warn', data)
}
async error(data: any) {
this.emit('error', data)
}
async info(data: any) {
this.emit('info', data)
async activateCustomScriptRunner(config: customScriptRunnerConfig) {
this.bridge.activateCustomScriptRunner(config)
}
async loadCustomConfig(): Promise<void> {
try {
const content = await this.plugin.call('fileManager', 'readFile', configFileName)
const parsed = JSON.parse(content)
this.customConfig = parsed
} catch (e) {
this.customConfig = {
defaultConfig: 'default',
customConfig: {
baseConfiguration: 'default',
dependencies: []
}
}
}
async saveCustomConfig(content: ScriptRunnerConfig) {
this.bridge.saveCustomConfig(content)
}
async openCustomConfig() {
try {
await this.plugin.call('fileManager', 'open', '.remix/script.config.json')
} catch (e) {
}
}
async loadConfigurations() {
try {
const response = await axios.get(`${baseUrl}/projects.json?timestamp=${Date.now()}`);
this.configurations = response.data;
// find the default otherwise pick the first one as the active
this.configurations.forEach((config) => {
if (config.name === (this.customConfig.defaultConfig)) {
this.activeConfig = config;
}
});
if (!this.activeConfig) {
this.activeConfig = this.configurations[0];
}
} catch (error) {
console.error("Error fetching the projects data:", error);
}
this.bridge.openCustomConfig()
}
async saveCustomConfig(content: ScriptRunnerConfig) {
if (content.customConfig.dependencies.length === 0 && content.defaultConfig === 'default') {
try {
const exists = await this.plugin.call('fileManager', 'exists', '.remix/script.config.json')
if (exists) {
await this.plugin.call('fileManager', 'remove', '.remix/script.config.json')
}
} catch (e) {
}
return
}
await this.plugin.call('fileManager', 'writeFile', '.remix/script.config.json', JSON.stringify(content, null, 2))
async selectScriptRunner(config: ProjectConfiguration) {
this.bridge.selectScriptRunner(config)
}
async activateCustomScriptRunner(config: customScriptRunnerConfig) {
try {
const result = await axios.post(customBuildUrl, config)
if (result.data.hash) {
const newConfig: ProjectConfiguration = {
name: result.data.hash,
title: 'Custom configuration',
publish: true,
description: `Extension of ${config.baseConfiguration}`,
dependencies: config.dependencies,
replacements: {},
errorStatus: false,
error: '',
isLoading: false
};
this.configurations.push(newConfig)
this.renderComponent()
await this.loadScriptRunner(result.data.hash)
}
return result.data.hash
} catch (error) {
let message
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log('Error status:', error.response.status);
console.log('Error data:', error.response.data); // This should give you the output being sent
console.log('Error headers:', error.response.headers);
if (error.response.data.error) {
if (isArray(error.response.data.error)) {
const message = `${error.response.data.error[0]}`
this.plugin.call('notification', 'alert', {
id: 'scriptalert',
message,
title: 'Error'
})
throw new Error(message)
}
message = `${error.response.data.error}`
}
message = `Uknown error: ${error.response.data}`
this.plugin.call('notification', 'alert', {
id: 'scriptalert',
message,
title: 'Error'
})
throw new Error(message)
} else if (error.request) {
// The request was made but no response was received
console.log('No response received:', error.request);
throw new Error('No response received')
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error message:', error.message);
throw new Error(error.message)
}
}
updateComponent(state: IScriptRunnerState) {
return <ScriptRunnerUI customConfig={state.customConfig} configurations={state.configurations} activeConfig={state.activeConfig} enableCustomScriptRunner={state.enableCustomScriptRunner} activateCustomScriptRunner={this.activateCustomScriptRunner.bind(this)} saveCustomConfig={this.saveCustomConfig.bind(this)} openCustomConfig={this.openCustomConfig.bind(this)} loadScriptRunner={this.selectScriptRunner.bind(this)} />
}
}
}

@ -32,7 +32,7 @@ export const ScriptRunnerUI = (props: ScriptRunnerUIProps) => {
}
return (
<div className="px-1">
<div className="px-1 pt-2">
<Accordion activeKey={activeKey} defaultActiveKey="default">
{configurations.filter((config) => config.publish).map((config: ProjectConfiguration, index) => (
<div key={index}>

@ -35,3 +35,11 @@ export interface ScriptRunnerConfig {
customConfig: customScriptRunnerConfig
}
export interface IScriptRunnerState {
customConfig: customScriptRunnerConfig
configurations: ProjectConfiguration[]
activeConfig: ProjectConfiguration
enableCustomScriptRunner: boolean
}

@ -243,7 +243,7 @@ export const TabsUI = (props: TabsUIProps) => {
data-id="script-config"
className="btn text-dark border-left ml-2 pr-0 py-0 d-flex"
onClick={async () => {
props.plugin.call('menuicons', 'select', 'scriptRunnerBridge')
props.plugin.call('manager', 'activatePlugin', 'UIScriptRunner')
}}
>
<i className="fa-kit fa-solid-gear-circle-play"></i>

Loading…
Cancel
Save