parent
962e28a0c0
commit
34718f43b2
@ -1,2 +1,3 @@ |
|||||||
export * from './lib/remix-ui-terminal' |
export * from './lib/remix-ui-terminal' |
||||||
export * from './lib/remix-ui-terminal-wrapper' |
export * from './lib/remix-ui-terminal-wrapper' |
||||||
|
export * from './lib/context' |
@ -1,100 +1,37 @@ |
|||||||
|
import { appPlatformTypes, platformContext } from '@remix-ui/app' |
||||||
import { CustomTooltip } from '@remix-ui/helper' |
import { CustomTooltip } from '@remix-ui/helper' |
||||||
import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line
|
import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line
|
||||||
import { FormattedMessage, useIntl } from 'react-intl' |
import { FormattedMessage, useIntl } from 'react-intl' |
||||||
import { listenOnNetworkAction } from '../actions/terminalAction' |
import { listenOnNetworkAction } from '../actions/terminalAction' |
||||||
import { TerminalContext } from '../context/context' |
import { TerminalContext } from '../context' |
||||||
import { RemixUiTerminalProps } from '../types/terminalTypes' |
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) => { |
export const RemixUITerminalBar = (props: RemixUiTerminalProps) => { |
||||||
const { newstate: state, dispatch } = useContext(TerminalContext) |
const { terminalState, xtermState } = useContext(TerminalContext) |
||||||
|
const platform = useContext(platformContext) |
||||||
const intl = useIntl() |
const intl = useIntl() |
||||||
const terminalMenu = useRef(null) |
const terminalMenu = useRef(null) |
||||||
|
|
||||||
function handleToggleTerminal(event: any): void { |
|
||||||
dispatch({ type: 'toggle' }) |
|
||||||
} |
|
||||||
|
|
||||||
useEffect(() => { |
|
||||||
props.plugin.call('layout', 'minimize', props.plugin.profile.name, !state.isOpen) |
|
||||||
}, [state.isOpen]) |
|
||||||
|
|
||||||
useEffect(() => { |
useEffect(() => { |
||||||
console.log('state change', state) |
props.plugin.call('layout', 'minimize', props.plugin.profile.name, !terminalState.isOpen) |
||||||
}, [state]) |
}, [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 (<> |
return (<> |
||||||
<div className="remix_ui_terminal_bar d-flex"> |
<div className="remix_ui_terminal_bar d-flex"> |
||||||
<div className="remix_ui_terminal_menu d-flex w-100 align-items-center position-relative border-top border-dark bg-light" ref={terminalMenu} data-id="terminalToggleMenu"> |
<div className="remix_ui_terminal_menu d-flex w-100 align-items-center position-relative border-top border-dark bg-light" ref={terminalMenu} data-id="terminalToggleMenu"> |
||||||
<CustomTooltip |
<RemixUITerminalMenuToggle {...props} /> |
||||||
placement="top" |
{platform === appPlatformTypes.desktop ? |
||||||
tooltipId="terminalToggle" |
<> |
||||||
tooltipClasses="text-nowrap" |
<RemixUITerminalMenuButtons {...props} /> |
||||||
tooltipText={state.isOpen ? <FormattedMessage id="terminal.hideTerminal" /> : <FormattedMessage id="terminal.showTerminal" />} |
{xtermState.showOutput? <RemixUITerminalMenu {...props} />: <RemixUIXtermMenu {...props} />} |
||||||
> |
</> : |
||||||
<i |
<RemixUITerminalMenu {...props} /> |
||||||
className={`mx-2 remix_ui_terminal_toggleTerminal fas ${state.isOpen ? 'fa-angle-double-down' : 'fa-angle-double-up'}`} |
} |
||||||
data-id="terminalToggleIcon" |
|
||||||
onClick={handleToggleTerminal} |
|
||||||
></i> |
|
||||||
</CustomTooltip> |
|
||||||
<div className="mx-2 remix_ui_terminal_console" id="clearConsole" data-id="terminalClearConsole" onClick={handleClearConsole}> |
|
||||||
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="terminal.clearConsole" />}> |
|
||||||
<i className="fas fa-ban" aria-hidden="true"></i> |
|
||||||
</CustomTooltip> |
|
||||||
</div> |
|
||||||
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="terminal.pendingTransactions" />}> |
|
||||||
<div className="mx-2">0</div> |
|
||||||
</CustomTooltip> |
|
||||||
<CustomTooltip |
|
||||||
placement="top" |
|
||||||
tooltipId="terminalClear" |
|
||||||
tooltipClasses="text-nowrap" |
|
||||||
tooltipText={intl.formatMessage({ id: state.isVM ? 'terminal.listenVM' : 'terminal.listenTitle' })} |
|
||||||
> |
|
||||||
<div className="h-80 mx-3 align-items-center remix_ui_terminal_listenOnNetwork custom-control custom-checkbox"> |
|
||||||
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={intl.formatMessage({ id: 'terminal.listenTitle' })}> |
|
||||||
<input |
|
||||||
className="custom-control-input" |
|
||||||
id="listenNetworkCheck" |
|
||||||
onChange={listenOnNetwork} |
|
||||||
type="checkbox" |
|
||||||
disabled={state.isVM} |
|
||||||
/> |
|
||||||
</CustomTooltip> |
|
||||||
<label |
|
||||||
className="form-check-label custom-control-label text-nowrap" |
|
||||||
style={{ paddingTop: '0.125rem' }} |
|
||||||
htmlFor="listenNetworkCheck" |
|
||||||
data-id="listenNetworkCheckInput" |
|
||||||
> |
|
||||||
<FormattedMessage id="terminal.listen" /> |
|
||||||
</label> |
|
||||||
</div> |
|
||||||
</CustomTooltip> |
|
||||||
<div className="remix_ui_terminal_search d-flex align-items-center h-100"> |
|
||||||
<i className="remix_ui_terminal_searchIcon d-flex align-items-center justify-content-center fas fa-search bg-light" aria-hidden="true"></i> |
|
||||||
<input |
|
||||||
onChange={(event) => 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="terminalInputSearch" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
</div> |
</div> |
||||||
</div></>) |
</div></>) |
||||||
} |
} |
@ -0,0 +1,25 @@ |
|||||||
|
import React, { useContext, useEffect } from 'react' // eslint-disable-line
|
||||||
|
import { TerminalContext } from '../context' |
||||||
|
import { RemixUiTerminalProps, SET_OPEN } from '../types/terminalTypes' |
||||||
|
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 ( |
||||||
|
<div> |
||||||
|
<button className={`btn btn-sm btn-secondary mr-2 ${!xtermState.showOutput ? 'xterm-btn-none' : 'xterm-btn-active'}`} onClick={selectOutput}>output</button> |
||||||
|
<button className={`btn btn-sm btn-secondary ${xtermState.terminalsEnabled ? '' : 'd-none'} ${xtermState.showOutput ? 'xterm-btn-none' : 'xterm-btn-active'}`} onClick={showTerminal}><span className="far fa-terminal border-0 ml-1"></span></button> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
@ -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 ( |
||||||
|
<> |
||||||
|
<CustomTooltip |
||||||
|
placement="top" |
||||||
|
tooltipId="terminalToggle" |
||||||
|
tooltipClasses="text-nowrap" |
||||||
|
tooltipText={terminalState.isOpen ? <FormattedMessage id="terminal.hideTerminal" /> : <FormattedMessage id="terminal.showTerminal" />} |
||||||
|
> |
||||||
|
<i |
||||||
|
className={`mx-2 remix_ui_terminal_toggleTerminal fas ${terminalState.isOpen ? 'fa-angle-double-down' : 'fa-angle-double-up'}`} |
||||||
|
data-id="terminalToggleIcon" |
||||||
|
onClick={handleToggleTerminal} |
||||||
|
></i> |
||||||
|
</CustomTooltip> |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
@ -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 (<> |
||||||
|
<div className="mx-2 remix_ui_terminal_console" id="clearConsole" data-id="terminalClearConsole" onClick={handleClearConsole}> |
||||||
|
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="terminal.clearConsole" />}> |
||||||
|
<i className="fas fa-ban" aria-hidden="true"></i> |
||||||
|
</CustomTooltip> |
||||||
|
</div> |
||||||
|
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="terminal.pendingTransactions" />}> |
||||||
|
<div className="mx-2">0</div> |
||||||
|
</CustomTooltip> |
||||||
|
<CustomTooltip |
||||||
|
placement="top" |
||||||
|
tooltipId="terminalClear" |
||||||
|
tooltipClasses="text-nowrap" |
||||||
|
tooltipText={intl.formatMessage({ id: terminalState.isVM ? 'terminal.listenVM' : 'terminal.listenTitle' })} |
||||||
|
> |
||||||
|
<div className="h-80 mx-3 align-items-center remix_ui_terminal_listenOnNetwork custom-control custom-checkbox"> |
||||||
|
<CustomTooltip placement="top" tooltipId="terminalClear" tooltipClasses="text-nowrap" tooltipText={intl.formatMessage({ id: 'terminal.listenTitle' })}> |
||||||
|
<input |
||||||
|
className="custom-control-input" |
||||||
|
id="listenNetworkCheck" |
||||||
|
onChange={listenOnNetwork} |
||||||
|
type="checkbox" |
||||||
|
disabled={terminalState.isVM} |
||||||
|
/> |
||||||
|
</CustomTooltip> |
||||||
|
<label |
||||||
|
className="form-check-label custom-control-label text-nowrap" |
||||||
|
style={{ paddingTop: '0.125rem' }} |
||||||
|
htmlFor="listenNetworkCheck" |
||||||
|
data-id="listenNetworkCheckInput" |
||||||
|
> |
||||||
|
<FormattedMessage id="terminal.listen" /> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</CustomTooltip> |
||||||
|
<div className="remix_ui_terminal_search d-flex align-items-center h-100"> |
||||||
|
<i className="remix_ui_terminal_searchIcon d-flex align-items-center justify-content-center fas fa-search bg-light" aria-hidden="true"></i> |
||||||
|
<input |
||||||
|
onChange={(event) => 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="terminalInputSearch" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</>) |
||||||
|
} |
@ -1,3 +0,0 @@ |
|||||||
import React from 'react' |
|
||||||
|
|
||||||
export const TerminalContext = React.createContext(null) |
|
@ -0,0 +1,11 @@ |
|||||||
|
import { Actions, xTerminalUiState } from '@remix-ui/xterm' |
||||||
|
import React, { Dispatch } from 'react' |
||||||
|
|
||||||
|
type terminalProviderContextType = { |
||||||
|
terminalState: any, |
||||||
|
dispatch: Dispatch<any>, |
||||||
|
xtermState: xTerminalUiState, |
||||||
|
dispatchXterm: Dispatch<Actions> |
||||||
|
} |
||||||
|
|
||||||
|
export const TerminalContext = React.createContext<terminalProviderContextType>(null) |
@ -1,22 +1,33 @@ |
|||||||
import React, { useReducer } from 'react' // eslint-disable-line
|
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 { RemixUITerminalBar } from './components/remix-ui-terminal-bar' |
||||||
import { TerminalContext } from './context/context' |
import { TerminalContext } from './context' |
||||||
import { initialState, registerCommandReducer } from './reducers/terminalReducer' |
import { initialState, registerCommandReducer } from './reducers/terminalReducer' |
||||||
import RemixUiTerminal from './remix-ui-terminal' |
import RemixUiTerminal from './remix-ui-terminal' |
||||||
import { RemixUiTerminalProps } from './types/terminalTypes' |
import { RemixUiTerminalProps } from './types/terminalTypes' |
||||||
|
|
||||||
export const RemixUITerminalWrapper = (props: RemixUiTerminalProps) => { |
export const RemixUITerminalWrapper = (props: RemixUiTerminalProps) => { |
||||||
const [newstate, dispatch] = useReducer(registerCommandReducer, initialState) |
const [terminalState, dispatch] = useReducer(registerCommandReducer, initialState) |
||||||
|
const [xtermState, dispatchXterm] = useReducer(xtermReducer, xTerminInitialState) |
||||||
|
const platform = useContext(platformContext) |
||||||
const providerState = { |
const providerState = { |
||||||
newstate, |
terminalState, |
||||||
dispatch |
dispatch, |
||||||
|
xtermState, |
||||||
|
dispatchXterm |
||||||
} |
} |
||||||
|
|
||||||
return (<> |
return (<> |
||||||
<TerminalContext.Provider value={providerState}> |
<TerminalContext.Provider value={providerState}> |
||||||
<RemixUITerminalBar {...props} /> |
<RemixUITerminalBar {...props} /> |
||||||
<RemixUiTerminal {...props} /> |
{platform !== appPlatformTypes.desktop && <RemixUiTerminal {...props} />} |
||||||
|
{platform === appPlatformTypes.desktop && |
||||||
|
<> |
||||||
|
<RemixUiTerminal visible={xtermState.showOutput} plugin={props.plugin} onReady={props.onReady} /> |
||||||
|
<RemixUiXterminals {...props} /> |
||||||
|
</> |
||||||
|
} |
||||||
</TerminalContext.Provider> |
</TerminalContext.Provider> |
||||||
</>) |
</>) |
||||||
} |
} |
@ -1,2 +1,5 @@ |
|||||||
export * from './lib/components/remix-ui-xterm' |
export * from './lib/components/remix-ui-xterm' |
||||||
export * from './lib/components/remix-ui-xterminals' |
export * from './lib/components/remix-ui-xterminals' |
||||||
|
export * from './lib/reducer' |
||||||
|
export * from './lib/types' |
||||||
|
export * from './lib/actions' |
@ -0,0 +1,27 @@ |
|||||||
|
import { Actions } from "@remix-ui/xterm" |
||||||
|
import { Plugin } from "@remixproject/engine" |
||||||
|
|
||||||
|
export const createTerminal = async (shell: string = '', plugin: Plugin, workingDir: string, dispatch: React.Dispatch<Actions>) => { |
||||||
|
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 } }) |
||||||
|
|
||||||
|
/* |
||||||
|
setTerminals(prevState => { |
||||||
|
// set all to hidden
|
||||||
|
prevState.forEach(xtermState => { |
||||||
|
xtermState.hidden = true |
||||||
|
}) |
||||||
|
return [...prevState, { |
||||||
|
pid: pid, |
||||||
|
queue: '', |
||||||
|
timeStamp: Date.now(), |
||||||
|
ref: null, |
||||||
|
hidden: false |
||||||
|
}] |
||||||
|
}) |
||||||
|
*/ |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
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<void> { |
||||||
|
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<void> { |
||||||
|
createTerminal(shell, props.plugin, xtermState.workingDir, dispatchXterm) |
||||||
|
} |
||||||
|
|
||||||
|
function onCloseTerminal(): void | PromiseLike<void> { |
||||||
|
const pid = xtermState.terminals.find(xtermState => xtermState.hidden === false).pid |
||||||
|
if (pid) |
||||||
|
props.plugin.call('xterm', 'closeTerminal', pid) |
||||||
|
} |
||||||
|
|
||||||
|
return (<> |
||||||
|
<div className={`${xtermState.showOutput ? 'd-none' : ''}`}> |
||||||
|
<button className="btn btn-sm btn-secondary mr-2" onClick={async () => onClearTerminal()}> |
||||||
|
<CustomTooltip tooltipText={<FormattedMessage id='xterm.clear' defaultMessage='Clear terminal' />}> |
||||||
|
<span className="far fa-ban border-0 p-0 m-0"></span> |
||||||
|
</CustomTooltip> |
||||||
|
</button> |
||||||
|
<button className="btn btn-sm btn-secondary" onClick={async () => onCreateTerminal()}> |
||||||
|
<CustomTooltip tooltipText={<FormattedMessage id='xterm.new' defaultMessage='New terminal' />}> |
||||||
|
<span className="far fa-plus border-0 p-0 m-0"></span> |
||||||
|
</CustomTooltip> |
||||||
|
</button> |
||||||
|
<Dropdown as={ButtonGroup}> |
||||||
|
<Dropdown.Toggle split variant="secondary" id="dropdown-split-basic" /> |
||||||
|
<Dropdown.Menu className='custom-dropdown-items remixui_menuwidth'> |
||||||
|
{xtermState.shells.map((shell, index) => { |
||||||
|
return (<Dropdown.Item key={index} onClick={async () => await onCreateTerminal(shell)}>{shell}</Dropdown.Item>) |
||||||
|
})} |
||||||
|
</Dropdown.Menu> |
||||||
|
</Dropdown> |
||||||
|
<button className="btn ml-2 btn-sm btn-secondary" onClick={onCloseTerminal}> |
||||||
|
<CustomTooltip tooltipText={<FormattedMessage id='xterm.close' defaultMessage='Close terminal' />}> |
||||||
|
<span className="far fa-trash border-0 ml-1"></span> |
||||||
|
</CustomTooltip> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</>) |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
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 |
||||||
|
} |
||||||
|
} |
@ -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<T extends keyof ActionPayloadTypes> { |
||||||
|
type: T, |
||||||
|
payload: ActionPayloadTypes[T] |
||||||
|
} |
||||||
|
|
||||||
|
export type Actions = {[A in keyof ActionPayloadTypes]: Action<A>}[keyof ActionPayloadTypes] |
Loading…
Reference in new issue