diff --git a/apps/remix-ide-e2e/src/commands/openFile.ts b/apps/remix-ide-e2e/src/commands/openFile.ts
index 7f7e7b2026..f214100eee 100644
--- a/apps/remix-ide-e2e/src/commands/openFile.ts
+++ b/apps/remix-ide-e2e/src/commands/openFile.ts
@@ -21,7 +21,7 @@ function openFile (browser: NightwatchBrowser, name: string, done: VoidFunction)
// if side panel is shown, check this is the file panel
browser.element('css selector', '[data-id="verticalIconsKindfilePanel"] img[data-id="selected"]', (result) => {
if (result.status === 0) {
- done()
+ done()
} else browser.clickLaunchIcon('filePanel').perform(() => {
done()
})
diff --git a/apps/remix-ide/src/app/panels/terminal.js b/apps/remix-ide/src/app/panels/terminal.tsx
similarity index 78%
rename from apps/remix-ide/src/app/panels/terminal.js
rename to apps/remix-ide/src/app/panels/terminal.tsx
index 5ad90adf00..3b93cd5c22 100644
--- a/apps/remix-ide/src/app/panels/terminal.js
+++ b/apps/remix-ide/src/app/panels/terminal.tsx
@@ -1,12 +1,12 @@
/* global Node, requestAnimationFrame */ // eslint-disable-line
import React from 'react' // eslint-disable-line
-import { RemixUiTerminal } from '@remix-ui/terminal' // eslint-disable-line
+import { RemixUiTerminal, RemixUITerminalWrapper } from '@remix-ui/terminal' // eslint-disable-line
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
import {Registry} from '@remix-project/remix-lib'
import { PluginViewWrapper } from '@remix-ui/helper'
import vm from 'vm'
-const EventManager = require('../../lib/events')
+import EventManager from '../../lib/events'
import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line
import { RemixUiXterminals } from '@remix-ui/xterm'
@@ -26,6 +26,34 @@ const profile = {
}
class Terminal extends Plugin {
+ fileImport: CompilerImports
+ event: any
+ globalRegistry: Registry
+ element: HTMLDivElement
+ eventsDecoder: any
+ txListener: any
+ _deps: { fileManager: any; editor: any; compilersArtefacts: any; offsetToLineColumnConverter: any }
+ commandHelp: { 'remix.loadgist(id)': string; 'remix.loadurl(url)': string; 'remix.execute(filepath)': string; 'remix.exeCurrent()': string; 'remix.help()': string }
+ blockchain: any
+ vm: typeof vm
+ _api: any
+ _opts: any
+ config: any
+ version: string
+ data: {
+ lineLength: any // ????
+ session: any[]; activeFilters: { commands: any; input: string }; filterFns: any
+ }
+ _view: { el: any; bar: any; input: any; term: any; journal: any; cli: any }
+ _components: any
+ _commands: any
+ commands: any
+ _JOURNAL: any[]
+ _jobs: any[]
+ _INDEX: any
+ _shell: any
+ dispatch: any
+ terminalApi: any
constructor(opts, api) {
super(profile)
this.fileImport = new CompilerImports()
@@ -75,7 +103,7 @@ class Terminal extends Plugin {
this._INDEX.commandsMain = {}
if (opts.shell) this._shell = opts.shell // ???
register(this)
- this.event.register('debuggingRequested', async (hash) => {
+ this.event.register('debuggingRequested', async (hash: any) => {
// TODO should probably be in the run module
if (!await this._opts.appManager.isActive('debugger')) await this._opts.appManager.activatePlugin('debugger')
this.call('menuicons', 'select', 'debugger')
@@ -114,13 +142,12 @@ class Terminal extends Plugin {
}
updateComponent(state) {
- return (Registry.getInstance().get('platform').api.isDesktop()) ?
-
- :
+ />)
}
renderComponent() {
diff --git a/libs/remix-ui/panel/src/lib/plugins/panel.css b/libs/remix-ui/panel/src/lib/plugins/panel.css
index f0cc402b55..437471fabb 100644
--- a/libs/remix-ui/panel/src/lib/plugins/panel.css
+++ b/libs/remix-ui/panel/src/lib/plugins/panel.css
@@ -104,7 +104,5 @@ iframe {
height: 2rem !important;
}
-
.terminal-wrap.minimized.desktop {
- height: 4.5rem !important;
}
diff --git a/libs/remix-ui/terminal/src/index.ts b/libs/remix-ui/terminal/src/index.ts
index 5b8eeca5b5..60fa49f835 100644
--- a/libs/remix-ui/terminal/src/index.ts
+++ b/libs/remix-ui/terminal/src/index.ts
@@ -1 +1,3 @@
export * from './lib/remix-ui-terminal'
+export * from './lib/remix-ui-terminal-wrapper'
+export * from './lib/context'
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-bar.tsx b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-bar.tsx
new file mode 100644
index 0000000000..f88efce844
--- /dev/null
+++ b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-bar.tsx
@@ -0,0 +1,41 @@
+import { appPlatformTypes, platformContext } from '@remix-ui/app'
+import { CustomTooltip } from '@remix-ui/helper'
+import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line
+import { FormattedMessage, useIntl } from 'react-intl'
+import { listenOnNetworkAction } from '../actions/terminalAction'
+import { TerminalContext } from '../context'
+import { RemixUiTerminalProps } from '../types/terminalTypes'
+import { RemixUITerminalMenu } from './remix-ui-terminal-menu'
+import { RemixUITerminalMenuToggle } from './remix-ui-terminal-menu-toggle'
+import { RemixUIXtermMenu } from '../../../../xterm/src/lib/components/remix-ui-terminal-menu-xterm'
+import { RemixUITerminalMenuButtons } from './remix-ui-terminal-menu-buttons'
+
+export const RemixUITerminalBar = (props: RemixUiTerminalProps) => {
+ const { terminalState, xtermState } = useContext(TerminalContext)
+ const platform = useContext(platformContext)
+ const intl = useIntl()
+ const terminalMenu = useRef(null)
+
+ useEffect(() => {
+ props.plugin.call('layout', 'minimize', props.plugin.profile.name, !terminalState.isOpen)
+ }, [terminalState.isOpen])
+
+ return (<>
+
+
+
+ {platform === appPlatformTypes.desktop ?
+
+
+ {xtermState.showOutput? : }
+
:
+
+ }
+
+
>
+ )
+}
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-buttons.css b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-buttons.css
new file mode 100644
index 0000000000..f4f8c73e76
--- /dev/null
+++ b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-buttons.css
@@ -0,0 +1,3 @@
+.xtermButton {
+ width: 4rem;;
+}
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-buttons.tsx b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-buttons.tsx
new file mode 100644
index 0000000000..7856a67e5d
--- /dev/null
+++ b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-buttons.tsx
@@ -0,0 +1,31 @@
+import React, { useContext, useEffect } from 'react' // eslint-disable-line
+import { TerminalContext } from '../context'
+import { RemixUiTerminalProps, SET_OPEN } from '../types/terminalTypes'
+import './remix-ui-terminal-menu-buttons.css'
+
+export const RemixUITerminalMenuButtons = (props: RemixUiTerminalProps) => {
+ const { xtermState, dispatchXterm, terminalState, dispatch } = useContext(TerminalContext)
+
+ function selectOutput(event: any): void {
+ props.plugin.call('layout', 'minimize', props.plugin.profile.name, false)
+ dispatchXterm({ type: 'SHOW_OUTPUT', payload: true })
+ dispatch({ type: SET_OPEN, payload: true })
+ }
+
+ function showTerminal(event: any): void {
+ props.plugin.call('layout', 'minimize', props.plugin.profile.name, false)
+ dispatchXterm({ type: 'SHOW_OUTPUT', payload: false })
+ dispatch({ type: SET_OPEN, payload: true })
+ }
+
+ return (
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-toggle.tsx b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-toggle.tsx
new file mode 100644
index 0000000000..0cfa811fc0
--- /dev/null
+++ b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu-toggle.tsx
@@ -0,0 +1,30 @@
+import { CustomTooltip } from '@remix-ui/helper'
+import React, { useContext, useEffect } from 'react' // eslint-disable-line
+import { FormattedMessage } from 'react-intl'
+import { TerminalContext } from '../context'
+import { RemixUiTerminalProps, TOGGLE } from '../types/terminalTypes'
+export const RemixUITerminalMenuToggle = (props: RemixUiTerminalProps) => {
+
+ const { terminalState, dispatch } = useContext(TerminalContext)
+
+ function handleToggleTerminal(event: any): void {
+ dispatch({ type: TOGGLE })
+ }
+
+ return (
+ <>
+ : }
+ >
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu.tsx b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu.tsx
new file mode 100644
index 0000000000..8eac46c62d
--- /dev/null
+++ b/libs/remix-ui/terminal/src/lib/components/remix-ui-terminal-menu.tsx
@@ -0,0 +1,76 @@
+import { CustomTooltip } from '@remix-ui/helper'
+import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line
+import { FormattedMessage, useIntl } from 'react-intl'
+import { listenOnNetworkAction } from '../actions/terminalAction'
+import { TerminalContext } from '../context'
+import { RemixUiTerminalProps } from '../types/terminalTypes'
+
+export const RemixUITerminalMenu = (props: RemixUiTerminalProps) => {
+ const { terminalState, dispatch } = useContext(TerminalContext)
+ const intl = useIntl()
+
+ useEffect(() => {
+ props.plugin.call('layout', 'minimize', props.plugin.profile.name, !terminalState.isOpen)
+ }, [terminalState.isOpen])
+
+ function handleClearConsole(event: any): void {
+ dispatch({ type: 'clearconsole', payload: [] })
+ }
+
+ function listenOnNetwork(event: any): void {
+ const isListening = event.target.checked
+ listenOnNetworkAction(props.plugin, isListening)
+ }
+
+ function setSearchInput(arg0: string): void {
+ dispatch({ type: 'search', payload: arg0 })
+ }
+
+ return (
+
}>
+
0
+
+
+
+
+
+
+
+
+
+
+
+ setSearchInput(event.target.value.trim())}
+ type="text"
+ className="remix_ui_terminal_filter border form-control"
+ id="searchInput"
+ placeholder={intl.formatMessage({ id: 'terminal.search' })}
+ data-id="terminalInputSearchTerminal"
+ />
+
+
+ }>
+
+
+
+
)
+}
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/context/index.ts b/libs/remix-ui/terminal/src/lib/context/index.ts
new file mode 100644
index 0000000000..810b3fba20
--- /dev/null
+++ b/libs/remix-ui/terminal/src/lib/context/index.ts
@@ -0,0 +1,11 @@
+import { Actions, xTerminalUiState } from '@remix-ui/xterm'
+import React, { Dispatch } from 'react'
+
+type terminalProviderContextType = {
+ terminalState: any,
+ dispatch: Dispatch,
+ xtermState: xTerminalUiState,
+ dispatchXterm: Dispatch
+}
+
+export const TerminalContext = React.createContext(null)
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts b/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts
index c451abfbb8..3b1ed4d469 100644
--- a/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts
+++ b/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts
@@ -1,85 +1,112 @@
-import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, TYPEWRITERLOG, TYPEWRITERWARNING, TYPEWRITERSUCCESS, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes'
+import {CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, TYPEWRITERLOG, TYPEWRITERWARNING, TYPEWRITERSUCCESS, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN, TOGGLE, SEARCH, SET_ISVM, SET_OPEN} from '../types/terminalTypes'
export const initialState = {
- journalBlocks: [
- ],
+ journalBlocks: [],
data: {
// lineLength: props.options.lineLength || 80,
session: [],
- activeFilters: { commands: {}, input: '' },
- filterFns: {}
+ activeFilters: {commands: {}, input: ''},
+ filterFns: {},
},
_commandHistory: [],
_commands: {},
commands: {},
_JOURNAL: [],
_jobs: [],
- _INDEX: {
- },
+ _INDEX: {},
_INDEXall: [],
_INDEXallMain: [],
_INDEXcommands: {},
_INDEXcommandsMain: {},
- message: []
+ message: [],
+ isOpen: true,
+ searchInput: '',
+ clearConsole: false,
+ isVM: true
}
export const registerCommandReducer = (state, action) => {
switch (action.type) {
- case HTML :
+ case HTML:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
- data: Object.assign(initialState.data, { ...action.payload.data })
+ data: Object.assign(initialState.data, {...action.payload.data}),
}
case LOG:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
- data: Object.assign(initialState.data, { ...action.payload.data })
-
+ data: Object.assign(initialState.data, {...action.payload.data}),
}
case INFO:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
- data: Object.assign(initialState.data, action.payload.data)
+ data: Object.assign(initialState.data, action.payload.data),
}
case WARN:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
- data: Object.assign(initialState.data, action.payload.data)
+ data: Object.assign(initialState.data, action.payload.data),
}
case ERROR:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
- data: Object.assign(initialState.data, action.payload.data)
+ data: Object.assign(initialState.data, action.payload.data),
}
case SCRIPT:
return {
...state,
_commands: Object.assign(initialState._commands, action.payload._commands),
commands: Object.assign(initialState.commands, action.payload.commands),
- data: Object.assign(initialState.data, action.payload.data)
+ data: Object.assign(initialState.data, action.payload.data),
}
case CLEAR_CONSOLE:
return {
...state,
- ...state.journalBlocks.splice(0)
+ ...state.journalBlocks.splice(0),
+ clearConsole: true,
+ }
+
+ case SEARCH:
+ return {
+ ...state,
+ searchInput: action.payload,
+ }
+
+ case TOGGLE:
+ return {
+ ...state,
+ isOpen: !state.isOpen,
}
+
+ case SET_OPEN:
+ return {
+ ...state,
+ isOpen: action.payload,
+ }
+
case LISTEN_ON_NETWORK:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log' })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: 'text-log'}),
}
- default :
- return { state }
+
+ case SET_ISVM:
+ return {
+ ...state,
+ isVM: action.payload,
+ }
+ default:
+ return {state}
}
}
@@ -88,31 +115,30 @@ export const registerFilterReducer = (state, action) => {
case LOG:
return {
...state,
- data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
-
+ data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns),
}
case INFO:
return {
...state,
- data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
+ data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns),
}
case WARN:
return {
...state,
- data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
+ data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns),
}
case ERROR:
return {
...state,
- data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
+ data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns),
}
case SCRIPT:
return {
...state,
- data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns)
+ data: Object.assign(initialState.data.filterFns, action.payload.data.filterFns),
}
- default :
- return { state }
+ default:
+ return {state}
}
}
@@ -121,20 +147,19 @@ export const addCommandHistoryReducer = (state, action) => {
case CMD_HISTORY:
return {
...state,
- _commandHistory: initialState._commandHistory.unshift(action.payload.script)
-
+ _commandHistory: initialState._commandHistory.unshift(action.payload.script),
}
- default :
- return { state }
+ default:
+ return {state}
}
}
export const remixWelcomeTextReducer = (state, action) => {
switch (action.type) {
- case 'welcomeText' :
+ case 'welcomeText':
return {
...state,
- journalBlocks: initialState.journalBlocks.push(action.payload.welcomeText)
+ journalBlocks: initialState.journalBlocks.push(action.payload.welcomeText),
}
}
}
@@ -144,67 +169,67 @@ export const registerScriptRunnerReducer = (state, action) => {
case HTML:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: 'text-log', provider: action.payload.provider}),
}
case LOG:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: 'text-log', provider: action.payload.provider}),
}
case TYPEWRITERLOG:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-log', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, typewriter: true, style: 'text-log', provider: action.payload.provider}),
}
case TYPEWRITERWARNING:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-warning', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, typewriter: true, style: 'text-warning', provider: action.payload.provider}),
}
case TYPEWRITERSUCCESS:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-success', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, typewriter: true, style: 'text-success', provider: action.payload.provider}),
}
case INFO:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-success', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: 'text-success', provider: action.payload.provider}),
}
case WARN:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-warning', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: 'text-warning', provider: action.payload.provider}),
}
case ERROR:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-danger', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: 'text-danger', provider: action.payload.provider}),
}
case SCRIPT:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: 'text-log', provider: action.payload.provider}),
}
case KNOWN_TRANSACTION:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '', name: 'knownTransaction', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: '', name: 'knownTransaction', provider: action.payload.provider}),
}
case UNKNOWN_TRANSACTION:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '', name: 'unknownTransaction', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: '', name: 'unknownTransaction', provider: action.payload.provider}),
}
case EMPTY_BLOCK:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '', name: 'emptyBlock', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: '', name: 'emptyBlock', provider: action.payload.provider}),
}
case NEW_TRANSACTION:
return {
...state,
- journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: '', provider: action.payload.provider })
+ journalBlocks: initialState.journalBlocks.push({message: action.payload.message, style: '', provider: action.payload.provider}),
}
}
}
diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal-wrapper.tsx b/libs/remix-ui/terminal/src/lib/remix-ui-terminal-wrapper.tsx
new file mode 100644
index 0000000000..d21123eaef
--- /dev/null
+++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal-wrapper.tsx
@@ -0,0 +1,33 @@
+import { appPlatformTypes, platformContext } from '@remix-ui/app'
+import { RemixUiXterminals, xTerminInitialState, xtermReducer } from '@remix-ui/xterm'
+import React, { useContext, useReducer } from 'react' // eslint-disable-line
+import { RemixUITerminalBar } from './components/remix-ui-terminal-bar'
+import { TerminalContext } from './context'
+import { initialState, registerCommandReducer } from './reducers/terminalReducer'
+import RemixUiTerminal from './remix-ui-terminal'
+import { RemixUiTerminalProps } from './types/terminalTypes'
+
+export const RemixUITerminalWrapper = (props: RemixUiTerminalProps) => {
+ const [terminalState, dispatch] = useReducer(registerCommandReducer, initialState)
+ const [xtermState, dispatchXterm] = useReducer(xtermReducer, xTerminInitialState)
+ const platform = useContext(platformContext)
+ const providerState = {
+ terminalState,
+ dispatch,
+ xtermState,
+ dispatchXterm
+ }
+
+ return (<>
+
+
+ {platform !== appPlatformTypes.desktop && }
+ {platform === appPlatformTypes.desktop &&
+ <>
+
+
+ >
+ }
+
+ >)
+}
\ No newline at end of file
diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.css b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
index 13402e45ee..fb9d6bf735 100644
--- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
+++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
@@ -19,7 +19,7 @@ element.style {
min-height : 3em;
}
.remix_ui_terminal_bar {
- z-index : 2;
+ z-index : 20;
}
.remix_ui_terminal_menu {
max-height : 35px;
diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
index 4c35d28981..3a16832b18 100644
--- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
+++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
-import React, { useState, useEffect, useReducer, useRef, SyntheticEvent, MouseEvent } from 'react' // eslint-disable-line
+import React, { useState, useEffect, useReducer, useRef, SyntheticEvent, MouseEvent, useContext } from 'react' // eslint-disable-line
import { FormattedMessage, useIntl } from 'react-intl'
import {
registerCommandAction,
@@ -27,8 +27,9 @@ import RenderUnKnownTransactions from './components/RenderUnknownTransactions' /
import RenderCall from './components/RenderCall' // eslint-disable-line
import RenderKnownTransactions from './components/RenderKnownTransactions' // eslint-disable-line
import parse from 'html-react-parser'
-import { EMPTY_BLOCK, KNOWN_TRANSACTION, RemixUiTerminalProps, UNKNOWN_TRANSACTION } from './types/terminalTypes'
+import { EMPTY_BLOCK, KNOWN_TRANSACTION, RemixUiTerminalProps, SET_ISVM, UNKNOWN_TRANSACTION } from './types/terminalTypes'
import { wrapScript } from './utils/wrapScript'
+import { TerminalContext } from './context'
const _paq = (window._paq = window._paq || [])
/* eslint-disable-next-line */
@@ -41,7 +42,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const [_cmdIndex, setCmdIndex] = useState(-1)
const [_cmdTemp, setCmdTemp] = useState('')
const [isOpen, setIsOpen] = useState(true)
- const [newstate, dispatch] = useReducer(registerCommandReducer, initialState)
+ const { terminalState, dispatch } = useContext(TerminalContext)
const [cmdHistory, cmdHistoryDispatch] = useReducer(addCommandHistoryReducer, initialState)
const [, scriptRunnerDispatch] = useReducer(registerScriptRunnerReducer, initialState)
const [toaster, setToaster] = useState(false)
@@ -59,7 +60,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
handleHide: () => {},
})
- const [clearConsole, setClearConsole] = useState(false)
const [isVM, setIsVM] = useState(false)
const [paste, setPaste] = useState(false)
const [storage, setStorage] = useState(null)
@@ -81,7 +81,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
commandHistoryIndex: 0,
})
- const [searchInput, setSearchInput] = useState('')
const [showTableHash, setShowTableHash] = useState([])
// terminal inputRef
@@ -101,7 +100,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
useEffect(() => {
props.plugin.on('network', 'providerChanged', (provider) => {
- setIsVM(provider.startsWith('vm-'))
+ dispatch({ type: SET_ISVM, payload: provider.startsWith('vm-') })
})
props.onReady({
@@ -132,10 +131,10 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
// events
useEffect(() => {
initListeningOnNetwork(props.plugin, scriptRunnerDispatch)
- registerLogScriptRunnerAction(on, 'log', newstate.commands, scriptRunnerDispatch)
- registerInfoScriptRunnerAction(on, 'info', newstate.commands, scriptRunnerDispatch)
- registerWarnScriptRunnerAction(on, 'warn', newstate.commands, scriptRunnerDispatch)
- registerErrorScriptRunnerAction(on, 'error', newstate.commands, scriptRunnerDispatch)
+ registerLogScriptRunnerAction(on, 'log', terminalState.commands, scriptRunnerDispatch)
+ registerInfoScriptRunnerAction(on, 'info', terminalState.commands, scriptRunnerDispatch)
+ registerWarnScriptRunnerAction(on, 'warn', terminalState.commands, scriptRunnerDispatch)
+ registerErrorScriptRunnerAction(on, 'error', terminalState.commands, scriptRunnerDispatch)
registerCommandAction('html', _blocksRenderer('html'), { activate: true }, dispatch)
registerCommandAction('log', _blocksRenderer('log'), { activate: true }, dispatch)
registerCommandAction('info', _blocksRenderer('info'), { activate: true }, dispatch)
@@ -158,7 +157,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
useEffect(() => {
scrollToBottom()
- }, [newstate.journalBlocks.length, toaster])
+ }, [terminalState.journalBlocks.length, toaster])
function execute(file, cb) {
function _execute(content, cb) {
@@ -167,7 +166,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
if (cb) cb()
return
}
- newstate.commands.script(content)
+ terminalState.commands.script(content)
}
if (typeof file === 'undefined') {
@@ -303,7 +302,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const script = autoCompletState.userInput.trim() // inputEl.current.innerText.trim()
if (script.length) {
cmdHistoryDispatch({ type: 'cmdHistory', payload: { script } })
- newstate.commands.script(wrapScript(script))
+ terminalState.commands.script(wrapScript(script))
}
setAutoCompleteState((prevState) => ({ ...prevState, userInput: '' }))
inputEl.current.innerText = ''
@@ -313,11 +312,11 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
showSuggestions: false,
}))
}
- } else if (newstate._commandHistory.length && event.which === 38 && !autoCompletState.showSuggestions && autoCompletState.userInput === '') {
+ } else if (terminalState._commandHistory.length && event.which === 38 && !autoCompletState.showSuggestions && autoCompletState.userInput === '') {
event.preventDefault()
setAutoCompleteState((prevState) => ({
...prevState,
- userInput: newstate._commandHistory[0],
+ userInput: terminalState._commandHistory[0],
}))
} else if (event.which === 38 && autoCompletState.showSuggestions) {
event.preventDefault()
@@ -397,21 +396,17 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
}
+ useEffect(() => {
+ if(terminalState.clearConsole){
+ typeWriterIndexes.current = []
+ inputEl.current.focus()
+ }
+ },[terminalState.clearConsole])
+
/* end of block content that gets rendered from script Runner */
- const handleClearConsole = () => {
- setClearConsole(true)
- typeWriterIndexes.current = []
- dispatch({ type: 'clearconsole', payload: [] })
- inputEl.current.focus()
- }
/* start of autoComplete */
- const listenOnNetwork = (e: any) => {
- const isListening = e.target.checked
- listenOnNetworkAction(props.plugin, isListening)
- }
-
const onChange = (event: any) => {
event.preventDefault()
const inputString = event.target.value
@@ -562,11 +557,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}))
}
- const handleToggleTerminal = () => {
- setIsOpen(!isOpen)
- props.plugin.call('layout', 'minimize', props.plugin.profile.name, isOpen)
- }
-
useEffect(() => {
;(async () => {
const storage = await props.plugin.call('storage', 'formatString', await props.plugin.call('storage', 'getStorage'))
@@ -601,76 +591,15 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
return (
- ( !props.visible? <>>:
-
-
-
-
:
}
- >
-
-
-
- }>
-
-
-
-
}>
-
0
-
-
-
-
-
-
-
-
-
-
-
- setSearchInput(event.target.value.trim())}
- type="text"
- className="remix_ui_terminal_filter border form-control"
- id="searchInput"
- placeholder={intl.formatMessage({ id: 'terminal.search' })}
- data-id="terminalInputSearchTerminal"
- />
-
-
-
+ ( props.visible &&
+
{handleAutoComplete()}
- {!clearConsole &&
}
- {newstate.journalBlocks &&
- newstate.journalBlocks.map((x, index) => {
+ {!terminalState.clearConsole &&
}
+ {terminalState.journalBlocks &&
+ terminalState.journalBlocks.map((x, index) => {
if (x.name === EMPTY_BLOCK) {
return (
@@ -683,7 +612,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
)
} else if (x.name === UNKNOWN_TRANSACTION) {
return x.message
- .filter((x) => includeSearch(x, searchInput))
+ .filter((x) => includeSearch(x, terminalState.searchInput))
.map((trans) => {
return (
@@ -705,7 +634,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
})
} else if (x.name === KNOWN_TRANSACTION) {
return x.message
- .filter((x) => includeSearch(x, searchInput))
+ .filter((x) => includeSearch(x, terminalState.searchInput))
.map((trans) => {
return (
@@ -738,7 +667,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
)
})
} else if (Array.isArray(x.message)) {
- if (searchInput !== '') return []
+ if (terminalState.searchInput !== '') return []
return x.message.map((msg, i) => {
// strictly check condition on 0, false, except undefined, NaN.
// if you type `undefined`, terminal automatically throws error, it's error message: "undefined" is not valid JSON
diff --git a/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts b/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts
index 29d5af476a..52e667badb 100644
--- a/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts
+++ b/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts
@@ -23,11 +23,15 @@ export const WARN = 'warn'
export const ERROR = 'error'
export const SCRIPT = 'script'
export const CLEAR_CONSOLE = 'clearconsole'
+export const TOGGLE = 'toggle'
+export const SET_OPEN = 'setOpen'
export const LISTEN_ON_NETWORK = 'listenOnNetWork'
export const CMD_HISTORY = 'cmdHistory'
+export const SEARCH = 'search'
+export const SET_ISVM = 'setIsVM'
export interface RemixUiTerminalProps {
- plugin: any,
- onReady: (api: any) => void,
- visible: boolean,
+ plugin: any,
+ onReady: (api: any) => void,
+ visible: boolean,
}
diff --git a/libs/remix-ui/xterm/src/index.ts b/libs/remix-ui/xterm/src/index.ts
index d0850bef79..6d438dd286 100644
--- a/libs/remix-ui/xterm/src/index.ts
+++ b/libs/remix-ui/xterm/src/index.ts
@@ -1,2 +1,5 @@
export * from './lib/components/remix-ui-xterm'
-export * from './lib/components/remix-ui-xterminals'
\ No newline at end of file
+export * from './lib/components/remix-ui-xterminals'
+export * from './lib/reducer'
+export * from './lib/types'
+export * from './lib/actions'
\ No newline at end of file
diff --git a/libs/remix-ui/xterm/src/lib/actions/index.ts b/libs/remix-ui/xterm/src/lib/actions/index.ts
new file mode 100644
index 0000000000..956c850296
--- /dev/null
+++ b/libs/remix-ui/xterm/src/lib/actions/index.ts
@@ -0,0 +1,12 @@
+import { Actions } from "@remix-ui/xterm"
+import { Plugin } from "@remixproject/engine"
+
+export const createTerminal = async (shell: string = '', plugin: Plugin, workingDir: string, dispatch: React.Dispatch
) => {
+ const shells: string[] = await plugin.call('xterm', 'getShells')
+ dispatch({ type: 'ADD_SHELLS', payload: shells })
+ const pid = await plugin.call('xterm', 'createTerminal', workingDir, shell)
+ dispatch({ type: 'SHOW_OUTPUT', payload: false })
+ dispatch({ type: 'HIDE_ALL_TERMINALS', payload: null })
+ dispatch({ type: 'ADD_TERMINAL', payload: { pid, queue: '', timeStamp: Date.now(), ref: null, hidden: false } })
+
+}
diff --git a/libs/remix-ui/xterm/src/lib/components/remix-ui-terminal-menu-xterm.tsx b/libs/remix-ui/xterm/src/lib/components/remix-ui-terminal-menu-xterm.tsx
new file mode 100644
index 0000000000..a2732762a8
--- /dev/null
+++ b/libs/remix-ui/xterm/src/lib/components/remix-ui-terminal-menu-xterm.tsx
@@ -0,0 +1,59 @@
+import { CustomTooltip } from '@remix-ui/helper';
+import { TerminalContext } from '@remix-ui/terminal';
+import { createTerminal } from '@remix-ui/xterm';
+import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line
+import { Dropdown, ButtonGroup } from 'react-bootstrap';
+import { FormattedMessage } from 'react-intl';
+import { RemixUiTerminalProps } from "../../../../terminal/src/lib/types/terminalTypes";
+
+export const RemixUIXtermMenu = (props: RemixUiTerminalProps) => {
+ const { xtermState, dispatchXterm } = useContext(TerminalContext)
+
+ function onClearTerminal(): void | PromiseLike {
+ const terminal = xtermState.terminals.find(xtermState => xtermState.hidden === false)
+ if (terminal && terminal.ref && terminal.ref.terminal)
+ terminal.ref.terminal.clear()
+ }
+
+ function onCreateTerminal(shell?: string): void | PromiseLike {
+ createTerminal(shell, props.plugin, xtermState.workingDir, dispatchXterm)
+ }
+
+ function onCloseTerminal(): void | PromiseLike {
+ const pid = xtermState.terminals.find(xtermState => xtermState.hidden === false).pid
+ if (pid)
+ props.plugin.call('xterm', 'closeTerminal', pid)
+ }
+
+ return (<>
+
+
onCreateTerminal()}>
+ }>
+
+
+
+
+ }>
+
+
+
+ {xtermState.shells.map((shell, index) => {
+ return ( await onCreateTerminal(shell)}>{shell})
+ })}
+
+
+
+
+
+ }>
+
+
+
+
onClearTerminal()}>
+ }>
+
+
+
+
+ >)
+}
\ No newline at end of file
diff --git a/libs/remix-ui/xterm/src/lib/components/remix-ui-xterm.tsx b/libs/remix-ui/xterm/src/lib/components/remix-ui-xterm.tsx
index 703b335f7f..7aa71d962b 100644
--- a/libs/remix-ui/xterm/src/lib/components/remix-ui-xterm.tsx
+++ b/libs/remix-ui/xterm/src/lib/components/remix-ui-xterm.tsx
@@ -54,8 +54,6 @@ const RemixUiXterm = (props: RemixUiXtermProps) => {
resize(event, pid)
}
-
-
return (
void
}
-export interface xtermState {
- pid: number
- queue: string
- timeStamp: number
- ref: any
- hidden: boolean
-}
-
export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
+ const { xtermState, dispatchXterm } = useContext(TerminalContext)
const [terminals, setTerminals] = useState([])
- const [workingDir, setWorkingDir] = useState('')
- const [showOutput, setShowOutput] = useState(true)
+ //const [workingDir, setWorkingDir] = useState('')
+
const [theme, setTheme] = useState(themeCollection[0])
- const [terminalsEnabled, setTerminalsEnabled] = useState(false)
- const [shells, setShells] = useState([])
+
const { plugin } = props
useEffect(() => {
@@ -36,43 +30,24 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
})
plugin.on('xterm', 'close', async (pid: number) => {
- setTerminals(prevState => {
- const removed = prevState.filter(xtermState => xtermState.pid !== pid)
- if (removed.length > 0)
- removed[removed.length - 1].hidden = false
- if (removed.length === 0)
- setShowOutput(true)
- return [...removed]
- })
+ dispatchXterm({ type: 'REMOVE_TERMINAL', payload: pid })
})
plugin.on('xterm', 'new', async (pid: number) => {
- setShowOutput(false)
- setTerminals(prevState => {
- // set all to hidden
- prevState.forEach(xtermState => {
- xtermState.hidden = true
- })
- return [...prevState, {
- pid: pid,
- queue: '',
- timeStamp: Date.now(),
- ref: null,
- hidden: false
- }]
- })
+ dispatchXterm({ type: 'SHOW_OUTPUT', payload: false })
+ dispatchXterm({ type: 'ADD_TERMINAL', payload: { pid, queue: '', timeStamp: Date.now(), ref: null, hidden: false } })
})
plugin.on('fs', 'workingDirChanged', (path: string) => {
- setWorkingDir(path)
- setTerminalsEnabled(true)
+ dispatchXterm({ type: 'SET_WORKING_DIR', payload: path })
+ dispatchXterm({ type: 'ENABLE_TERMINALS', payload: null })
})
const workingDir = await plugin.call('fs', 'getWorkingDir')
if(workingDir && workingDir !== '') {
- setTerminalsEnabled(true)
- setWorkingDir(workingDir)
+ dispatchXterm({ type: 'ENABLE_TERMINALS', payload: null })
+ dispatchXterm({ type: 'SET_WORKING_DIR', payload: workingDir })
}
plugin.on('theme', 'themeChanged', async (theme) => {
@@ -97,6 +72,12 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
}, 2000)
}, [])
+ useEffect(() => {
+ setTerminals(xtermState.terminals)
+ if(xtermState.terminals.length === 0) {
+ dispatchXterm({ type: 'SHOW_OUTPUT', payload: true })
+ }
+ }, [xtermState.terminals])
const handleThemeChange = (theme: any) => {
themeCollection.forEach((themeItem) => {
@@ -129,27 +110,6 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
plugin.call('xterm', 'resize', event, pid)
}
-
- const createTerminal = async (shell?: string) => {
- const shells = await plugin.call('xterm', 'getShells')
- setShells(shells)
- const pid = await plugin.call('xterm', 'createTerminal', workingDir, shell)
- setShowOutput(false)
- setTerminals(prevState => {
- // set all to hidden
- prevState.forEach(xtermState => {
- xtermState.hidden = true
- })
- return [...prevState, {
- pid: pid,
- queue: '',
- timeStamp: Date.now(),
- ref: null,
- hidden: false
- }]
- })
- }
-
const setTerminalRef = (pid: number, ref: any) => {
setTerminals(prevState => {
const terminal = prevState.find(xtermState => xtermState.pid === pid)
@@ -174,93 +134,46 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
})
}
- const closeTerminal = () => {
- const pid = terminals.find(xtermState => xtermState.hidden === false).pid
- if (pid)
- plugin.call('xterm', 'closeTerminal', pid)
- }
-
- const selectOutput = () => {
- props.plugin.call('layout', 'minimize', props.plugin.profile.name, false)
- setShowOutput(true)
- }
-
- const showTerminal = () => {
- setShowOutput(false)
- props.plugin.call('layout', 'minimize', props.plugin.profile.name, false)
- if (terminals.length === 0) createTerminal()
- }
-
- const clearTerminal = () => {
- const terminal = terminals.find(xtermState => xtermState.hidden === false)
- if (terminal && terminal.ref && terminal.ref.terminal)
- terminal.ref.terminal.clear()
- }
+ useEffect(() => {
+ if (!xtermState.showOutput) {
+ if (terminals.length === 0) createTerminal('', plugin, xtermState.workingDir, dispatchXterm)
+ }
+ }, [xtermState.showOutput])
return (<>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {shells.map((shell, index) => {
- return ( await createTerminal(shell)}>{shell})
- })}
-
-
-
-
-
-
-
-
-
+ {
<>
-
-
+ {
{terminals.map((xtermState) => {
return (
-
-
+
+
)
})}
-
+
{terminals.map((xtermState, index) => {
- return ()
+ return ()
})}
+ }
>
-
-
-
+
}
>)
}
@@ -313,4 +226,4 @@ const themeCollection = [
themeName: 'Pride', backgroundColor: '#f1eef6', textColor: '#343a40',
shapeColor: '#343a40', fillColor: '#f8fafe'
},
-]
\ No newline at end of file
+]
diff --git a/libs/remix-ui/xterm/src/lib/components/xterm-wrap.tsx b/libs/remix-ui/xterm/src/lib/components/xterm-wrap.tsx
index 03b54ccf6f..4998c3e750 100644
--- a/libs/remix-ui/xterm/src/lib/components/xterm-wrap.tsx
+++ b/libs/remix-ui/xterm/src/lib/components/xterm-wrap.tsx
@@ -232,6 +232,6 @@ export class Xterm extends React.Component
{
}
render() {
- return
+ return
}
}
\ No newline at end of file
diff --git a/libs/remix-ui/xterm/src/lib/css/index.css b/libs/remix-ui/xterm/src/lib/css/index.css
index d7a13a031f..5912949212 100644
--- a/libs/remix-ui/xterm/src/lib/css/index.css
+++ b/libs/remix-ui/xterm/src/lib/css/index.css
@@ -1,70 +1,4 @@
-.remix-ui-xterminals-container {
- display: flex;
- flex-direction: row;
- flex: 1;
-}
-.xterm-panel {
- display: flex;
- flex-direction: column;
- flex: 1;
-}
-
-.remix-ui-xterminals-buttons {
- display: flex;
- flex-direction: column;
-}
-
-.hide-xterm{
- display: none;
-}
-
-.show-xterm{
- display: block;
-}
-
-.xterm-btn-active {
- background-color: var(--primary);
-}
-.xterm-btn-none {
- background-color: var(--secondary);
-}
-
-.xterm-terminal {
- flex-grow: 1;
- height: 100%;
- width: 100%;
-}
-
-.xterm-panel-header-right {
- display: flex;
- flex-direction: row;
- justify-content: flex-end;
- align-self: flex-end;
-}
-
-.xterm-panel-header {
- display: flex;
- flex-direction: row;
-
-}
-
-.xterm-panel-header-left {
- display: flex;
- flex-direction: row;
- flex-grow: 1;
-}
-
-.remix-ui-xterminals-section {
- display: flex;
- flex-direction: row;
- width: 100%;
- z-index: 3;
-}
-
-.hide-terminals {
- width: 0;
-}
-
-.show-terminals {
- width: 100%;
+.xterm-panel-left {
+ overflow-y: scroll;
+ margin-bottom: 2.1rem;
}
diff --git a/libs/remix-ui/xterm/src/lib/reducer/index.ts b/libs/remix-ui/xterm/src/lib/reducer/index.ts
new file mode 100644
index 0000000000..a96d218523
--- /dev/null
+++ b/libs/remix-ui/xterm/src/lib/reducer/index.ts
@@ -0,0 +1,70 @@
+import { Actions, xTerminalUiState } from "@remix-ui/xterm"
+
+export const xTerminInitialState: xTerminalUiState = {
+ terminalsEnabled: false,
+ terminals: [],
+ shells: [],
+ showOutput: true,
+ workingDir: ''
+}
+
+export const xtermReducer = (state = xTerminInitialState, action: Actions) => {
+ switch (action.type) {
+ case 'ENABLE_TERMINALS':
+ return {
+ ...state,
+ terminalsEnabled: true
+ }
+ case 'DISABLE_TERMINALS':
+ return {
+ ...state,
+ terminalsEnabled: false
+ }
+ case 'ADD_TERMINAL':
+ return {
+ ...state,
+ terminals: [...state.terminals, action.payload]
+ }
+ case 'HIDE_TERMINAL':
+ return {
+ ...state,
+ terminals: state.terminals.map(terminal => terminal.pid === action.payload ? { ...terminal, hidden: true } : terminal)
+ }
+ case 'SHOW_TERMINAL':
+ return {
+ ...state,
+ terminals: state.terminals.map(terminal => terminal.pid === action.payload ? { ...terminal, hidden: false } : terminal)
+ }
+ case 'HIDE_ALL_TERMINALS':
+ return {
+ ...state,
+ terminals: state.terminals.map(terminal => ({ ...terminal, hidden: true }))
+ }
+ case 'REMOVE_TERMINAL': {
+ const removed = state.terminals.filter(xtermState => xtermState.pid !== action.payload)
+ if (removed.length > 0)
+ removed[removed.length - 1].hidden = false
+ return {
+ ...state,
+ terminals: removed
+ }
+ }
+ case 'ADD_SHELLS':
+ return {
+ ...state,
+ shells: action.payload
+ }
+ case 'SHOW_OUTPUT':
+ return {
+ ...state,
+ showOutput: action.payload
+ }
+ case 'SET_WORKING_DIR':
+ return {
+ ...state,
+ workingDir: action.payload
+ }
+ default:
+ return state
+ }
+}
diff --git a/libs/remix-ui/xterm/src/lib/types/index.ts b/libs/remix-ui/xterm/src/lib/types/index.ts
new file mode 100644
index 0000000000..170441acb9
--- /dev/null
+++ b/libs/remix-ui/xterm/src/lib/types/index.ts
@@ -0,0 +1,36 @@
+
+export interface xtermState {
+ pid: number
+ queue: string
+ timeStamp: number
+ ref: any
+ hidden: boolean
+}
+
+export interface xTerminalUiState {
+ terminalsEnabled: boolean
+ terminals: xtermState[]
+ shells: string[]
+ showOutput: boolean
+ workingDir: string
+}
+
+export interface ActionPayloadTypes {
+ ENABLE_TERMINALS: undefined,
+ DISABLE_TERMINALS: undefined,
+ ADD_TERMINAL: xtermState,
+ HIDE_TERMINAL: number,
+ SHOW_TERMINAL: number,
+ HIDE_ALL_TERMINALS: undefined,
+ REMOVE_TERMINAL: number,
+ ADD_SHELLS: string[],
+ SHOW_OUTPUT: boolean
+ SET_WORKING_DIR: string
+}
+
+export interface Action {
+ type: T,
+ payload: ActionPayloadTypes[T]
+}
+
+export type Actions = {[A in keyof ActionPayloadTypes]: Action}[keyof ActionPayloadTypes]
\ No newline at end of file