1- import React , { createRef } from 'react' ;
1+ import React , { createRef , useEffect } from 'react' ;
22import { Terminal } from 'xterm' ;
33import * as TerminalFit from 'xterm/lib/addons/fit/fit' ;
44import SpinnerOverlay from '@/components/elements/SpinnerOverlay' ;
5- import { connect } from 'react-redux' ;
6- import { Websocket } from '@/plugins/Websocket' ;
7- import { ServerStore } from '@/state/server' ;
5+ import { ServerContext } from '@/state/server' ;
86
97const theme = {
108 background : 'transparent' ,
@@ -27,94 +25,71 @@ const theme = {
2725 brightWhite : '#ffffff' ,
2826} ;
2927
30- interface Props {
31- connected : boolean ;
32- instance : Websocket | null ;
33- }
28+ const terminal = new Terminal ( {
29+ disableStdin : true ,
30+ cursorStyle : 'underline' ,
31+ allowTransparency : true ,
32+ fontSize : 12 ,
33+ fontFamily : 'Menlo, Monaco, Consolas, monospace' ,
34+ rows : 30 ,
35+ theme : theme ,
36+ } ) ;
3437
35- class Console extends React . PureComponent < Readonly < Props > > {
36- ref = createRef < HTMLDivElement > ( ) ;
37- terminal = new Terminal ( {
38- disableStdin : true ,
39- cursorStyle : 'underline' ,
40- allowTransparency : true ,
41- fontSize : 12 ,
42- fontFamily : 'Menlo, Monaco, Consolas, monospace' ,
43- rows : 30 ,
44- theme : theme ,
45- } ) ;
38+ export default ( ) => {
39+ const ref = createRef < HTMLDivElement > ( ) ;
40+ const connected = ServerContext . useStoreState ( state => state . socket . connected ) ;
41+ const instance = ServerContext . useStoreState ( state => state . socket . instance ) ;
4642
47- componentDidMount ( ) {
48- if ( this . ref . current ) {
49- this . terminal . open ( this . ref . current ) ;
50- this . terminal . clear ( ) ;
43+ const handleConsoleOutput = ( line : string ) => terminal . writeln (
44+ line . replace ( / (?: \r \n | \r | \n ) $ / im, '' ) + '\u001b[0m' ,
45+ ) ;
46+
47+ useEffect ( ( ) => {
48+ if ( ref . current ) {
49+ terminal . open ( ref . current ) ;
5150
5251 // @see https://github.com/xtermjs/xterm.js/issues/2265
5352 // @see https://github.com/xtermjs/xterm.js/issues/2230
54- TerminalFit . fit ( this . terminal ) ;
53+ TerminalFit . fit ( terminal ) ;
5554 }
55+ } , [ ref . current ] ) ;
5656
57- if ( this . props . connected && this . props . instance ) {
58- this . listenForEvents ( ) ;
59- }
60- }
57+ useEffect ( ( ) => {
58+ if ( connected && instance ) {
59+ terminal . clear ( ) ;
6160
62- componentDidUpdate ( prevProps : Readonly < Readonly < Props > > ) {
63- if ( ! prevProps . connected && this . props . connected ) {
64- this . listenForEvents ( ) ;
65- }
66- }
61+ instance
62+ . addListener ( 'stats' , data => console . log ( JSON . parse ( data ) ) )
63+ . addListener ( 'console output' , handleConsoleOutput ) ;
6764
68- componentWillUnmount ( ) {
69- if ( this . props . instance ) {
70- this . props . instance . removeListener ( 'server log' , this . handleServerLog ) ;
71- this . props . instance . removeListener ( 'server log' , this . handleConsoleOutput ) ;
65+ instance . send ( 'send logs' ) ;
7266 }
73- }
7467
75- listenForEvents ( ) {
76- const instance = this . props . instance ! ;
68+ return ( ) => {
69+ instance && instance
70+ . removeListener ( 'console output' , handleConsoleOutput )
71+ . removeAllListeners ( 'stats' ) ;
72+ } ;
73+ } , [ connected , instance ] ) ;
7774
78- instance . addListener ( 'server log' , this . handleServerLog ) ;
79- instance . addListener ( 'console output' , this . handleConsoleOutput ) ;
80- instance . send ( 'send logs' ) ;
81- }
82-
83- handleServerLog = ( lines : string [ ] ) => lines . forEach ( data => {
84- return data . split ( / \n / g) . forEach ( line => this . terminal . writeln ( line + '\u001b[0m' ) ) ;
85- } ) ;
86-
87- handleConsoleOutput = ( line : string ) => this . terminal . writeln (
88- line . replace ( / (?: \r \n | \r | \n ) $ / im, '' ) + '\u001b[0m'
89- ) ;
90-
91- render ( ) {
92- return (
93- < div className = { 'text-xs font-mono relative' } >
94- < SpinnerOverlay visible = { ! this . props . connected } size = { 'large' } />
95- < div
96- className = { 'rounded-t p-2 bg-black overflow-scroll w-full' }
97- style = { {
98- minHeight : '16rem' ,
99- maxHeight : '64rem' ,
100- } }
101- >
102- < div id = { 'terminal' } ref = { this . ref } />
103- </ div >
104- < div className = { 'rounded-b bg-neutral-900 text-neutral-100 flex' } >
105- < div className = { 'flex-no-shrink p-2 font-bold' } > $</ div >
106- < div className = { 'w-full' } >
107- < input type = { 'text' } className = { 'bg-transparent text-neutral-100 p-2 pl-0 w-full' } />
108- </ div >
75+ return (
76+ < div className = { 'text-xs font-mono relative' } >
77+ < SpinnerOverlay visible = { ! connected } size = { 'large' } />
78+ < div
79+ className = { 'rounded-t p-2 bg-black overflow-scroll w-full' }
80+ style = { {
81+ minHeight : '16rem' ,
82+ maxHeight : '64rem' ,
83+ } }
84+ >
85+ < div id = { 'terminal' } ref = { ref } />
86+ </ div >
87+ < div className = { 'rounded-b bg-neutral-900 text-neutral-100 flex' } >
88+ < div className = { 'flex-no-shrink p-2 font-bold' } > $</ div >
89+ < div className = { 'w-full' } >
90+ < input type = { 'text' } className = { 'bg-transparent text-neutral-100 p-2 pl-0 w-full' } />
10991 </ div >
11092 </ div >
111- ) ;
112- }
113- }
114-
115- export default connect (
116- ( state : ServerStore ) => ( {
117- connected : state . socket . connected ,
118- instance : state . socket . instance ,
119- } ) ,
120- ) ( Console ) ;
93+ </ div >
94+ ) ;
95+ } ;
0 commit comments