rdesktop2
filip mertens 1 year ago
parent 297c476b21
commit 731aecd556
  1. 29
      apps/remix-ide/src/app/panels/terminal.js
  2. 4
      apps/remix-ide/src/app/plugins/electron/isoGitPlugin.ts
  3. 1
      apps/remixdesktop/src/plugins/fsPlugin.ts
  4. 12
      apps/remixdesktop/src/plugins/xtermPlugin.ts
  5. 1
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  6. 7
      libs/remix-ui/panel/src/lib/dragbar/dragbar.tsx
  7. 11
      libs/remix-ui/xterm/src/lib/components/remix-ui-xterm.tsx
  8. 152
      libs/remix-ui/xterm/src/lib/components/remix-ui-xterminals.tsx
  9. 46
      libs/remix-ui/xterm/src/lib/css/index.css

@ -9,11 +9,12 @@ import vm from 'vm'
const EventManager = require('../../lib/events')
import { CompilerImports } from '@remix-project/core-plugin' // eslint-disable-line
import { RemixUiXterminals } from '@remix-ui/xterm'
const KONSOLES = []
function register (api) { KONSOLES.push(api) }
function register(api) { KONSOLES.push(api) }
const profile = {
displayName: 'Terminal',
@ -25,7 +26,7 @@ const profile = {
}
class Terminal extends Plugin {
constructor (opts, api) {
constructor(opts, api) {
super(profile)
this.fileImport = new CompilerImports()
this.event = new EventManager()
@ -89,18 +90,18 @@ class Terminal extends Plugin {
this.renderComponent()
}
onDeactivation () {
onDeactivation() {
this.off('scriptRunner', 'log')
this.off('scriptRunner', 'info')
this.off('scriptRunner', 'warn')
this.off('scriptRunner', 'error')
}
logHtml (html) {
logHtml(html) {
this.terminalApi.logHtml(html)
}
log (message, type) {
log(message, type) {
this.terminalApi.log(message, type)
}
@ -108,18 +109,20 @@ class Terminal extends Plugin {
this.dispatch = dispatch
}
render () {
return <div id='terminal-view' className='panel' data-id='terminalContainer-view'><PluginViewWrapper plugin={this}/></div>
render() {
return <div id='terminal-view' className='panel' data-id='terminalContainer-view'><PluginViewWrapper plugin={this} /></div>
}
updateComponent(state) {
return <RemixUiTerminal
plugin={state.plugin}
onReady={state.onReady}
/>
return isElectron() ? <RemixUiXterminals onReady={state.onReady} plugin={state.plugin}>
</RemixUiXterminals>
: <RemixUiTerminal
plugin={state.plugin}
onReady={state.onReady}
/>
}
renderComponent () {
renderComponent() {
const onReady = (api) => { this.terminalApi = api }
this.dispatch({
plugin: this,
@ -127,7 +130,7 @@ class Terminal extends Plugin {
})
}
scroll2bottom () {
scroll2bottom() {
setTimeout(function () {
// do nothing.
}, 0)

@ -16,9 +16,9 @@ export class isoGitPlugin extends ElectronPlugin {
setTimeout(async () => {
const version = await this.call('isogit', 'version')
if(version){
this.call('terminal', 'log', version)
//this.call('terminal', 'log', version)
}else{
this.call('terminal', 'log', 'Git is not installed on the system. Using builtin git instead. Performance will be affected. It is better to install git on the system and configure the credentials to connect to GitHub etc.')
//this.call('terminal', 'log', 'Git is not installed on the system. Using builtin git instead. Performance will be affected. It is better to install git on the system and configure the credentials to connect to GitHub etc.')
}

@ -138,7 +138,6 @@ class FSPluginClient extends ElectronBasePluginClient {
withFileTypes: true,
...options
})
console.log('glob', files)
const result: any[] = []
for (const file of files) {

@ -55,7 +55,7 @@ const clientProfile: Profile = {
name: 'xterm',
displayName: 'xterm',
description: 'xterm plugin',
methods: ['createTerminal', 'close', 'keystroke']
methods: ['createTerminal', 'close', 'keystroke', 'getShells']
}
class XtermPluginClient extends ElectronBasePluginClient {
@ -65,13 +65,23 @@ class XtermPluginClient extends ElectronBasePluginClient {
super(webContentsId, profile)
this.onload(() => {
console.log('XtermPluginClient onload')
this.emit('loaded')
})
}
async onActivation(): Promise<void> {
console.log('XtermPluginClient onActivation')
}
async keystroke(key: string, pid: number): Promise<void> {
this.terminals[pid].write(key)
}
async getShells(): Promise<string[]> {
return [defaultShell]
}
async createTerminal(path?: string): Promise<number> {
const shell = defaultShell;

@ -91,7 +91,6 @@ const RemixApp = (props: IRemixAppUi) => {
<DragBar resetTrigger={resetTrigger} maximiseTrigger={maximiseTrigger} minWidth={285} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar>
<div id="main-panel" data-id="remixIdeMainPanel" className='mainpanel d-flex'>
<RemixUIMainPanel Context={AppContext}></RemixUIMainPanel>
<RemixUiXterminals plugin={props.app.appManager}></RemixUiXterminals>
<CustomTooltip
placement="bottom"
tooltipId="overlay-tooltip-all-tabs"

@ -16,15 +16,18 @@ const DragBar = (props: IRemixDragBarUi) => {
const nodeRef = React.useRef(null) // fix for strictmode
function stopDrag (e: MouseEvent, data: any) {
console.log('stopDrag', data)
const h = window.innerHeight - data.y
props.refObject.current.setAttribute('style', `height: ${h}px;`)
setDragBarPosY(window.innerHeight - props.refObject.current.offsetHeight)
console.log('stopDrag', `height: ${h}px;`)
setDragBarPosY(props.refObject.current.offsetTop)
setDragState(false)
props.setHideStatus(false)
}
const handleResize = () => {
console.log('handleResize', props.refObject.current)
if (!props.refObject.current) return
setDragBarPosY(window.innerHeight - props.refObject.current.offsetHeight)
setDragBarPosY(props.refObject.current.offsetTop)
}
useEffect(() => {

@ -9,6 +9,10 @@ export interface RemixUiXtermProps {
send: (data: string, pid: number) => void
timeStamp: number
setTerminalRef: (pid: number, ref: any) => void
theme: {
backgroundColor: string
textColor: string
}
}
const RemixUiXterm = (props: RemixUiXtermProps) => {
@ -38,8 +42,11 @@ const RemixUiXterm = (props: RemixUiXtermProps) => {
return (
<>
<button className='btn' onClick={closeTerminal}>close</button>
<XTerm ref={xtermRef} onData={onData} onKey={onKey}></XTerm>
<button className='btn d-none' onClick={closeTerminal}>close</button>
<XTerm
options={{theme: {background: props.theme.backgroundColor , foreground: props.theme.textColor}}}
ref={xtermRef} onData={onData}
onKey={onKey}></XTerm>
</>
)

@ -2,9 +2,12 @@ import React, { useState, useEffect } from 'react' // eslint-disable-line
import { ElectronPlugin } from '@remixproject/engine-electron'
import RemixUiXterm from './remix-ui-xterm'
import '../css/index.css'
import { Tab, Tabs } from 'react-bootstrap'
import { Button, ButtonGroup, Dropdown, Tab, Tabs } from 'react-bootstrap'
import { CustomIconsToggle } from '@remix-ui/helper'
import { RemixUiTerminal } from '@remix-ui/terminal'
export interface RemixUiXterminalsProps {
plugin: ElectronPlugin
onReady: (api: any) => void
}
export interface xtermState {
@ -18,30 +21,65 @@ export interface xtermState {
export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
const [terminals, setTerminals] = useState<xtermState[]>([])
const [workingDir, setWorkingDir] = useState<string>('')
const [showOutput, setShowOutput] = useState<boolean>(true)
const [theme, setTheme] = useState<any>(themeCollection[0])
const [terminalsEnabled, setTerminalsEnabled] = useState<boolean>(false)
const [shells, setShells] = useState<string[]>([])
const { plugin } = props
useEffect(() => {
setTimeout(async () => {
plugin.on('xterm', 'loaded', async () => {
console.log('xterm loaded')
})
plugin.on('xterm', 'data', async (data: string, pid: number) => {
writeToTerminal(data, pid)
})
plugin.on('xterm', 'close', async (pid: number) => {
setTerminals(prevState => {
const removed = prevState.filter(xtermState => xtermState.pid !== pid)
removed[removed.length-1].hidden = false
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]
})
})
plugin.on('fs', 'workingDirChanged', (path: string) => {
setWorkingDir(path)
setTerminalsEnabled(true)
})
plugin.on('theme', 'themeChanged', async (theme) => {
console.log('themeChanged', theme)
handleThemeChange(theme)
})
}, 5000)
const theme = await plugin.call('theme', 'currentTheme')
console.log('theme', theme)
handleThemeChange(theme)
const shells = await plugin.call('xterm', 'getShells')
console.log('shells', shells)
setShells(shells)
}, 2000)
}, [])
const handleThemeChange = (theme: any) => {
themeCollection.forEach((themeItem) => {
if (themeItem.themeName === theme.name) {
setTheme(themeItem)
console.log('setTheme', themeItem)
}
})
}
const writeToTerminal = (data: string, pid: number) => {
setTerminals(prevState => {
const terminal = prevState.find(xtermState => xtermState.pid === pid)
@ -67,7 +105,7 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
const createTerminal = async () => {
const pid = await plugin.call('xterm', 'createTerminal', workingDir)
setShowOutput(false)
setTerminals(prevState => {
// set all to hidden
prevState.forEach(xtermState => {
@ -108,33 +146,101 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
})
}
const closeTerminal = () => {
const pid = terminals.find(xtermState => xtermState.hidden === false).pid
if (pid)
plugin.call('xterm', 'close', pid)
}
return (<>
const selectOutput = () => {
setShowOutput(true)
}
<div className='xterm-panel'>
<button className='btn btn-sm btn-secondary' onClick={() => {
createTerminal()
}}>open new terminal</button>
const showTerminal = () => {
setShowOutput(false)
if (terminals.length === 0) createTerminal()
}
<div className='remix-ui-xterminals-container'>
<>
{terminals.map((xtermState, index) => {
return (<>
return (<button onClick={async () => selectTerminal(xtermState)} className={`btn btn-sm btn-secondary ${xtermState.hidden ? 'xterm-btn-none' : 'xterm-btn-active'}`}>Terminal {index + 1}</button>)
})}
{terminals.map((xtermState) => {
return (
<div className={xtermState.hidden ? 'hide-xterm' : 'show-xterm'} key={xtermState.pid} data-id={`remixUIXT${xtermState.pid}`}>
<RemixUiXterm setTerminalRef={setTerminalRef} timeStamp={xtermState.timeStamp} send={send} pid={xtermState.pid} plugin={plugin}></RemixUiXterm>
<div className='xterm-panel'>
<div className='xterm-panel-header bg-light'>
<div className='xterm-panel-header-left p-1'>
<button className={`btn btn-sm btn-secondary mr-2 ${!showOutput ? 'xterm-btn-none' : 'xterm-btn-active'}`} onClick={selectOutput}>ouput</button>
<button className={`btn btn-sm btn-secondary ${terminalsEnabled ? '' : 'd-none'} ${showOutput ? 'xterm-btn-none' : 'xterm-btn-active'}`} onClick={showTerminal}><span className="far fa-terminal border-0 ml-1"></span></button>
</div>
<div className={`xterm-panel-header-right ${showOutput ? 'd-none' : ''}`}>
<Dropdown as={ButtonGroup}>
<button className="btn btn-sm btn-secondary" onClick={createTerminal}><span className="far fa-plus border-0 p-0 m-0"></span></button>
<Dropdown.Toggle split variant="secondary" id="dropdown-split-basic" />
<Dropdown.Menu className='custom-dropdown-items remixui_menuwidth'>
{shells.map((shell, index) => {
return (<Dropdown.Item index={index} onClick={createTerminal}>{shell}</Dropdown.Item>)
})}
</Dropdown.Menu>
</Dropdown>
<button className="btn ml-2 btn-sm btn-secondary" onClick={closeTerminal}><span className="far fa-trash border-0 ml-1"></span></button>
</div>
</div>
<div className='remix-ui-xterminals-container'>
<>
<div className={`${!showOutput ? 'd-none' : 'd-block w-100'} `}>
<RemixUiTerminal
plugin={props.plugin}
onReady={props.onReady} />
</div>
<div className={`remix-ui-xterminals-section ${showOutput ? 'd-none' : 'd-flex'} `}>
{terminals.map((xtermState) => {
return (
<div className={`xterm-terminal ${xtermState.hidden ? 'hide-xterm' : 'show-xterm'}`} key={xtermState.pid} data-id={`remixUIXT${xtermState.pid}`}>
<RemixUiXterm theme={theme} setTerminalRef={setTerminalRef} timeStamp={xtermState.timeStamp} send={send} pid={xtermState.pid} plugin={plugin}></RemixUiXterm>
</div>
)
})}
<div className='remix-ui-xterminals-buttons border-left'>
{terminals.map((xtermState, index) => {
return (<button onClick={async () => selectTerminal(xtermState)} className={`btn btn-sm mt-2 btn-secondary ${xtermState.hidden ? 'xterm-btn-none' : 'xterm-btn-active'}`}><span className="fa fa-terminal border-0 p-0 m-0"></span></button>)
})}
</div>
)
})}
</>
</div>
</div>
</>
</div>
</div>
</>)
}
const themeCollection = [
{ themeName: 'HackerOwl', backgroundColor: '#011628', textColor: '#babbcc',
shapeColor: '#8694a1',fillColor: '#011C32'},
{ themeName: 'Cerulean', backgroundColor: '#ffffff', textColor: '#343a40',
shapeColor: '#343a40',fillColor: '#f8f9fa'},
{ themeName: 'Cyborg', backgroundColor: '#060606', textColor: '#adafae',
shapeColor: '#adafae', fillColor: '#222222'},
{ themeName: 'Dark', backgroundColor: '#222336', textColor: '#babbcc',
shapeColor: '#babbcc',fillColor: '#2a2c3f'},
{ themeName: 'Flatly', backgroundColor: '#ffffff', textColor: '#343a40',
shapeColor: '#7b8a8b',fillColor: '#ffffff'},
{ themeName: 'Black', backgroundColor: '#1a1a1a', textColor: '#babbcc',
shapeColor: '#b5b4bc',fillColor: '#1f2020'},
{ themeName: 'Light', backgroundColor: '#eef1f6', textColor: '#3b445e',
shapeColor: '#343a40',fillColor: '#ffffff'},
{ themeName: 'Midcentury', backgroundColor: '#DBE2E0', textColor: '#11556c',
shapeColor: '#343a40',fillColor: '#eeede9'},
{ themeName: 'Spacelab', backgroundColor: '#ffffff', textColor: '#343a40',
shapeColor: '#333333', fillColor: '#eeeeee'},
{ themeName: 'Candy', backgroundColor: '#d5efff', textColor: '#11556c',
shapeColor: '#343a40',fillColor: '#fbe7f8' },
{ themeName: 'Violet', backgroundColor: '#f1eef6', textColor: '#3b445e',
shapeColor: '#343a40',fillColor: '#f8fafe' },
{ themeName: 'Pride', backgroundColor: '#f1eef6', textColor: '#343a40',
shapeColor: '#343a40',fillColor: '#f8fafe' },
]

@ -1,7 +1,12 @@
.remix-ui-xterminals-container {
overflow: scroll;
display: flex;
flex-direction: row;
}
.xterm-panel {
}
.remix-ui-xterminals-buttons {
display: flex;
flex-direction: column;
}
@ -20,3 +25,42 @@
.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%;
}

Loading…
Cancel
Save