2022-06-08 02:25:35 +02:00
import * as React from "react" ;
import * as mobxReact from "mobx-react" ;
import * as mobx from "mobx" ;
import { sprintf } from "sprintf-js" ;
import { boundMethod } from "autobind-decorator" ;
2023-03-14 19:48:14 +01:00
import { If , For , When , Otherwise , Choose } from "tsx-control-statements/components" ;
import cn from "classnames" ;
2022-10-08 03:25:47 +02:00
import { debounce , throttle } from "throttle-debounce" ;
2022-07-14 08:11:45 +02:00
import { v4 as uuidv4 } from "uuid" ;
2022-09-06 02:21:31 +02:00
import dayjs from "dayjs" ;
2023-03-31 03:14:52 +02:00
import type { SessionDataType , LineType , CmdDataType , RemoteType , RemoteStateType , RemoteInstanceType , RemotePtrType , HistoryItem , HistoryQueryOpts , RemoteEditType , FeStateType , ContextMenuOpts , BookmarkType , RenderModeType , ClientMigrationInfo , LineFactoryProps } from "./types" ;
2023-03-03 19:16:31 +01:00
import type * as T from "./types" ;
2022-06-18 02:54:14 +02:00
import localizedFormat from 'dayjs/plugin/localizedFormat' ;
2023-03-29 07:53:18 +02:00
import { GlobalModel , GlobalCommandRunner , Session , Cmd , ScreenLines , Screen , riToRPtr , TabColors , RemoteColors } from "./model" ;
2023-04-04 08:17:15 +02:00
import { windowWidthToCols , windowHeightToRows , termHeightFromRows , termWidthFromCols , getMonoFontSize } from "./textmeasure" ;
2023-04-05 06:54:20 +02:00
import { isModKeyPress , boundInt , sortAndFilterRemotes , makeExternLink , isBlank } from "./util" ;
2023-02-23 18:21:37 +01:00
import { BookmarksView } from "./bookmarks" ;
2023-04-05 08:26:34 +02:00
import { WebShareView } from "./webshare-client-view" ;
2023-03-02 09:33:10 +01:00
import { HistoryView } from "./history" ;
import { Line , Prompt } from "./linecomps" ;
2023-04-03 20:29:54 +02:00
import { ScreenSettingsModal , SessionSettingsModal , LineSettingsModal , ClientSettingsModal } from "./settings" ;
import { RemotesModal } from "./remotes" ;
2023-04-04 23:04:44 +02:00
import { renderCmdText , RemoteStatusLight , Markdown } from "./elements" ;
2023-03-31 03:14:52 +02:00
import { LinesView } from "./linesview" ;
2023-04-05 06:54:20 +02:00
import { TosModal } from "./modals" ;
2022-06-18 02:54:14 +02:00
dayjs . extend ( localizedFormat )
2022-06-13 20:12:39 +02:00
2022-09-16 02:10:02 +02:00
const RemotePtyRows = 8 ;
2022-09-15 09:18:20 +02:00
const RemotePtyCols = 80 ;
2022-10-04 04:05:52 +02:00
const PasswordUnchangedSentinel = "--unchanged--" ;
2022-10-08 03:25:47 +02:00
const LinesVisiblePadding = 500 ;
2023-03-15 19:14:28 +01:00
const TDots = "⋮" ;
2022-09-15 09:18:20 +02:00
2022-10-08 03:25:47 +02:00
type OV < V > = mobx . IObservableValue < V > ;
type OArr < V > = mobx . IObservableArray < V > ;
type OMap < K , V > = mobx . ObservableMap < K , V > ;
2023-02-24 08:24:26 +01:00
type VisType = "visible" | "" ;
2023-02-06 09:31:34 +01:00
2022-08-13 03:34:56 +02:00
type InterObsValue = {
sessionid : string ,
lineid : string ,
cmdid : string ,
visible : mobx.IObservableValue < boolean > ,
timeoutid? : any ,
} ;
2022-08-29 22:54:11 +02:00
function scrollDiv ( div : any , amt : number ) {
if ( div == null ) {
return ;
}
let newScrollTop = div . scrollTop + amt ;
if ( newScrollTop < 0 ) {
newScrollTop = 0 ;
}
div . scrollTo ( { top : newScrollTop , behavior : "smooth" } ) ;
}
2023-03-15 19:14:28 +01:00
function truncateWithTDots ( str : string , maxLen : number ) : string {
if ( str == null ) {
return null ;
}
if ( str . length <= maxLen ) {
return str ;
}
return str . slice ( 0 , maxLen - 1 ) + TDots ;
}
2022-08-30 00:42:50 +02:00
function pageSize ( div : any ) : number {
if ( div == null ) {
return 300 ;
}
let size = div . clientHeight ;
if ( size > 500 ) {
size = size - 100 ;
} else if ( size > 200 ) {
size = size - 30 ;
}
return size ;
}
2022-06-08 02:25:35 +02:00
@mobxReact . observer
2023-02-24 02:51:59 +01:00
class TextAreaInput extends React . Component < { onHeightChange : ( ) = > void } , { } > {
2022-08-12 20:44:29 +02:00
lastTab : boolean = false ;
lastHistoryUpDown : boolean = false ;
2022-08-11 03:35:18 +02:00
lastTabCurLine : mobx.IObservableValue < string > = mobx . observable . box ( null ) ;
2022-10-11 08:44:04 +02:00
lastFocusType : string = null ;
mainInputRef : React.RefObject < any > ;
historyInputRef : React.RefObject < any > ;
2023-02-24 02:51:59 +01:00
controlRef : React.RefObject < any > ;
lastHeight : number = 0 ;
2022-10-11 08:44:04 +02:00
constructor ( props ) {
super ( props ) ;
this . mainInputRef = React . createRef ( ) ;
this . historyInputRef = React . createRef ( ) ;
2023-02-24 02:51:59 +01:00
this . controlRef = React . createRef ( ) ;
2022-10-11 08:44:04 +02:00
}
setFocus ( ) : void {
let inputModel = GlobalModel . inputModel ;
if ( inputModel . historyShow . get ( ) ) {
this . historyInputRef . current . focus ( ) ;
}
else {
this . mainInputRef . current . focus ( ) ;
}
}
2023-04-04 08:17:15 +02:00
getTextAreaMaxCols ( ) : number {
let taElem = this . mainInputRef . current ;
if ( taElem == null ) {
return 0 ;
}
let cs = window . getComputedStyle ( taElem ) ;
let padding = parseFloat ( cs . paddingLeft ) + parseFloat ( cs . paddingRight ) ;
let borders = parseFloat ( cs . borderLeft ) + parseFloat ( cs . borderRight ) ;
let contentWidth = taElem . clientWidth - padding - borders ;
let fontSize = getMonoFontSize ( parseInt ( cs . fontSize ) ) ;
let maxCols = Math . floor ( contentWidth / fontSize . width ) ;
console . log ( "getareamaxcols" , contentWidth , fontSize , maxCols ) ;
return maxCols ;
}
2023-02-24 02:51:59 +01:00
checkHeight ( shouldFire : boolean ) : void {
let elem = this . controlRef . current ;
if ( elem == null ) {
return ;
}
let curHeight = elem . offsetHeight ;
if ( this . lastHeight == curHeight ) {
return ;
}
this . lastHeight = curHeight ;
if ( shouldFire && this . props . onHeightChange != null ) {
this . props . onHeightChange ( ) ;
}
}
2022-08-24 02:27:12 +02:00
componentDidMount() {
2023-03-13 20:09:17 +01:00
let activeScreen = GlobalModel . getActiveScreen ( ) ;
if ( activeScreen != null ) {
let focusType = activeScreen . focusType . get ( ) ;
2022-10-11 08:44:04 +02:00
if ( focusType == "input" ) {
this . setFocus ( ) ;
}
this . lastFocusType = focusType ;
}
2023-02-24 02:51:59 +01:00
this . checkHeight ( false ) ;
2022-10-11 08:44:04 +02:00
}
componentDidUpdate() {
2023-03-13 20:09:17 +01:00
let activeScreen = GlobalModel . getActiveScreen ( ) ;
if ( activeScreen != null ) {
let focusType = activeScreen . focusType . get ( ) ;
2022-10-11 08:44:04 +02:00
if ( this . lastFocusType != focusType && focusType == "input" ) {
this . setFocus ( ) ;
}
this . lastFocusType = focusType ;
2022-08-24 02:27:12 +02:00
}
2022-11-11 03:52:38 +01:00
let inputModel = GlobalModel . inputModel ;
if ( inputModel . forceCursorPos . get ( ) != null ) {
if ( this . mainInputRef . current != null ) {
this . mainInputRef . current . selectionStart = inputModel . forceCursorPos . get ( ) ;
this . mainInputRef . current . selectionEnd = inputModel . forceCursorPos . get ( ) ;
}
mobx . action ( ( ) = > inputModel . forceCursorPos . set ( null ) ) ( ) ;
}
2023-02-24 02:51:59 +01:00
this . checkHeight ( true ) ;
2022-08-24 02:27:12 +02:00
}
2022-08-12 20:44:29 +02:00
getLinePos ( elem : any ) : { numLines : number , linePos : number } {
let numLines = elem . value . split ( "\n" ) . length ;
let linePos = elem . value . substr ( 0 , elem . selectionStart ) . split ( "\n" ) . length ;
return { numLines , linePos } ;
}
2022-06-08 02:25:35 +02:00
@mobx . action @boundMethod
onKeyDown ( e : any ) {
mobx . action ( ( ) = > {
2022-10-14 03:58:21 +02:00
if ( isModKeyPress ( e ) ) {
2022-08-12 20:44:29 +02:00
return ;
}
2022-07-11 23:43:18 +02:00
let model = GlobalModel ;
2022-08-11 03:35:18 +02:00
let inputModel = model . inputModel ;
2023-03-15 04:09:59 +01:00
let win = model . getScreenLinesForActiveScreen ( ) ;
2022-06-08 02:25:35 +02:00
let ctrlMod = e . getModifierState ( "Control" ) || e . getModifierState ( "Meta" ) || e . getModifierState ( "Shift" ) ;
2022-08-11 03:35:18 +02:00
let curLine = inputModel . getCurLine ( ) ;
2022-08-12 20:44:29 +02:00
let lastTab = this . lastTab ;
this . lastTab = ( e . code == "Tab" ) ;
let lastHist = this . lastHistoryUpDown ;
this . lastHistoryUpDown = false ;
2022-08-11 03:35:18 +02:00
if ( e . code == "Tab" ) {
e . preventDefault ( ) ;
if ( lastTab ) {
2022-11-23 23:34:05 +01:00
GlobalModel . submitCommand ( "_compgen" , null , [ curLine ] , { "comppos" : String ( curLine . length ) , "compshow" : "1" , "nohist" : "1" } , true ) ;
2022-08-11 03:35:18 +02:00
return ;
}
else {
2022-11-23 23:34:05 +01:00
GlobalModel . submitCommand ( "_compgen" , null , [ curLine ] , { "comppos" : String ( curLine . length ) , "nohist" : "1" } , true ) ;
2022-08-11 03:35:18 +02:00
return ;
}
}
2022-08-12 20:44:29 +02:00
if ( e . code == "Enter" ) {
2022-06-08 02:25:35 +02:00
e . preventDefault ( ) ;
2022-08-12 20:44:29 +02:00
if ( ! ctrlMod ) {
2023-02-01 07:22:51 +01:00
if ( GlobalModel . inputModel . isEmpty ( ) ) {
2023-03-15 04:09:59 +01:00
let activeWindow = GlobalModel . getScreenLinesForActiveScreen ( ) ;
2023-03-13 20:09:17 +01:00
let activeScreen = GlobalModel . getActiveScreen ( ) ;
if ( activeScreen != null && activeWindow != null && activeWindow . lines . length > 0 ) {
activeScreen . setSelectedLine ( 0 ) ;
GlobalCommandRunner . screenSelectLine ( "E" ) ;
2023-02-01 07:22:51 +01:00
}
return ;
}
else {
setTimeout ( ( ) = > GlobalModel . inputModel . uiSubmitCommand ( ) , 0 ) ;
return ;
}
2022-08-12 20:44:29 +02:00
}
e . target . setRangeText ( "\n" , e . target . selectionStart , e . target . selectionEnd , "end" ) ;
GlobalModel . inputModel . setCurLine ( e . target . value ) ;
2022-06-08 02:25:35 +02:00
return ;
}
2022-08-11 03:35:18 +02:00
if ( e . code == "Escape" ) {
2022-08-09 01:22:36 +02:00
e . preventDefault ( ) ;
2022-12-25 22:03:34 +01:00
e . stopPropagation ( ) ;
2022-10-23 08:54:46 +02:00
let inputModel = GlobalModel . inputModel ;
inputModel . toggleInfoMsg ( ) ;
if ( inputModel . inputMode . get ( ) != null ) {
inputModel . resetInputMode ( ) ;
}
2022-08-11 03:35:18 +02:00
return ;
}
if ( e . code == "KeyC" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
2022-08-31 08:12:37 +02:00
inputModel . resetInput ( ) ;
2022-08-09 01:22:36 +02:00
return ;
}
2023-03-08 05:40:30 +01:00
if ( e . code == "KeyU" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
this . controlU ( ) ;
return ;
}
2023-03-23 18:00:45 +01:00
if ( e . code == "KeyP" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
this . controlP ( ) ;
return ;
}
if ( e . code == "KeyN" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
this . controlN ( ) ;
return ;
}
2023-03-18 00:21:43 +01:00
if ( e . code == "KeyW" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
this . controlW ( ) ;
return ;
}
2023-03-08 05:40:30 +01:00
if ( e . code == "KeyY" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
this . controlY ( ) ;
return ;
}
2022-08-31 02:05:35 +02:00
if ( e . code == "KeyR" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
2022-08-31 08:12:37 +02:00
inputModel . openHistory ( ) ;
2022-08-31 02:05:35 +02:00
return ;
}
2023-02-22 07:10:45 +01:00
if ( e . code == "ArrowUp" && e . getModifierState ( "Shift" ) ) {
e . preventDefault ( ) ;
inputModel . openHistory ( ) ;
return ;
}
2022-08-12 20:44:29 +02:00
if ( e . code == "ArrowUp" || e . code == "ArrowDown" ) {
2022-08-31 08:12:37 +02:00
if ( ! inputModel . isHistoryLoaded ( ) ) {
if ( e . code == "ArrowUp" ) {
2022-08-31 22:29:59 +02:00
this . lastHistoryUpDown = true ;
2023-03-15 00:38:26 +01:00
inputModel . loadHistory ( false , 1 , "screen" ) ;
2022-08-31 08:12:37 +02:00
}
2022-08-31 02:05:35 +02:00
return ;
}
2022-08-31 08:12:37 +02:00
// invisible history movement
2022-08-12 20:44:29 +02:00
let linePos = this . getLinePos ( e . target ) ;
if ( e . code == "ArrowUp" ) {
if ( ! lastHist && linePos . linePos > 1 ) {
// regular arrow
return ;
}
e . preventDefault ( ) ;
2022-08-31 08:12:37 +02:00
inputModel . moveHistorySelection ( 1 ) ;
2022-08-12 20:44:29 +02:00
this . lastHistoryUpDown = true ;
return ;
}
if ( e . code == "ArrowDown" ) {
if ( ! lastHist && linePos . linePos < linePos . numLines ) {
// regular arrow
return ;
}
e . preventDefault ( ) ;
2022-08-31 08:12:37 +02:00
inputModel . moveHistorySelection ( - 1 ) ;
2022-08-12 20:44:29 +02:00
this . lastHistoryUpDown = true ;
return ;
}
2022-06-21 01:06:37 +02:00
}
2022-08-29 22:54:11 +02:00
if ( e . code == "PageUp" || e . code == "PageDown" ) {
e . preventDefault ( ) ;
2022-08-31 02:05:35 +02:00
let infoScroll = inputModel . hasScrollingInfoMsg ( ) ;
2022-08-29 22:54:11 +02:00
if ( infoScroll ) {
2022-08-30 00:42:50 +02:00
let div = document . querySelector ( ".cmd-input-info" ) ;
let amt = pageSize ( div ) ;
scrollDiv ( div , ( e . code == "PageUp" ? - amt : amt ) ) ;
2022-08-29 22:54:11 +02:00
}
}
2022-06-13 20:12:39 +02:00
// console.log(e.code, e.keyCode, e.key, event.which, ctrlMod, e);
2022-06-08 02:25:35 +02:00
} ) ( ) ;
}
@boundMethod
onChange ( e : any ) {
mobx . action ( ( ) = > {
2022-08-11 03:35:18 +02:00
GlobalModel . inputModel . setCurLine ( e . target . value ) ;
2022-06-08 02:25:35 +02:00
} ) ( ) ;
}
2022-06-13 20:12:39 +02:00
2022-08-31 08:12:37 +02:00
@boundMethod
onHistoryKeyDown ( e : any ) {
let inputModel = GlobalModel . inputModel ;
if ( e . code == "Escape" ) {
e . preventDefault ( ) ;
inputModel . resetHistory ( ) ;
return ;
}
if ( e . code == "Enter" ) {
e . preventDefault ( ) ;
inputModel . grabSelectedHistoryItem ( ) ;
return ;
}
2022-10-23 08:54:46 +02:00
if ( e . code == "KeyG" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
inputModel . resetInput ( ) ;
return ;
}
2022-08-31 08:12:37 +02:00
if ( e . code == "KeyC" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
inputModel . resetInput ( ) ;
return ;
}
2022-08-31 22:29:59 +02:00
if ( e . code == "KeyR" && ( ( e . getModifierState ( "Meta" ) || e . getModifierState ( "Control" ) ) && ! e . getModifierState ( "Shift" ) ) ) {
2022-08-31 21:00:53 +02:00
e . preventDefault ( ) ;
let opts = mobx . toJS ( inputModel . historyQueryOpts . get ( ) ) ;
if ( opts . limitRemote ) {
opts . limitRemote = false ;
opts . limitRemoteInstance = false ;
}
else {
opts . limitRemote = true ;
opts . limitRemoteInstance = true ;
}
inputModel . setHistoryQueryOpts ( opts ) ;
return ;
2022-08-31 09:02:16 +02:00
}
2022-08-31 22:29:59 +02:00
if ( e . code == "KeyS" && ( e . getModifierState ( "Meta" ) || e . getModifierState ( "Control" ) ) ) {
e . preventDefault ( ) ;
let opts = mobx . toJS ( inputModel . historyQueryOpts . get ( ) ) ;
let htype = opts . queryType ;
2023-03-15 00:38:26 +01:00
if ( htype == "screen" ) {
2022-08-31 22:29:59 +02:00
htype = "session" ;
}
else if ( htype == "session" ) {
htype = "global" ;
}
else {
2023-03-15 00:38:26 +01:00
htype = "screen" ;
2022-08-31 22:29:59 +02:00
}
inputModel . setHistoryType ( htype ) ;
return ;
}
2022-08-31 08:12:37 +02:00
if ( e . code == "Tab" ) {
e . preventDefault ( ) ;
return ;
}
if ( e . code == "ArrowUp" || e . code == "ArrowDown" ) {
e . preventDefault ( ) ;
inputModel . moveHistorySelection ( e . code == "ArrowUp" ? 1 : - 1 ) ;
return ;
}
if ( e . code == "PageUp" || e . code == "PageDown" ) {
e . preventDefault ( ) ;
inputModel . moveHistorySelection ( e . code == "PageUp" ? 10 : - 10 ) ;
return ;
}
2023-03-23 18:00:45 +01:00
if ( e . code == "KeyP" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
inputModel . moveHistorySelection ( 1 ) ;
return ;
}
if ( e . code == "KeyN" && e . getModifierState ( "Control" ) ) {
e . preventDefault ( ) ;
inputModel . moveHistorySelection ( - 1 ) ;
return ;
}
2022-08-31 08:12:37 +02:00
}
2023-03-08 05:40:30 +01:00
@boundMethod
controlU() {
if ( this . mainInputRef . current == null ) {
return ;
}
let selStart = this . mainInputRef . current . selectionStart ;
let value = this . mainInputRef . current . value ;
if ( selStart > value . length ) {
return ;
}
let cutValue = value . substr ( 0 , selStart ) ;
let restValue = value . substr ( selStart ) ;
let cmdLineUpdate = { cmdline : restValue , cursorpos : 0 } ;
console . log ( "ss" , selStart , value , "[" + cutValue + "]" , "[" + restValue + "]" ) ;
navigator . clipboard . writeText ( cutValue ) ;
GlobalModel . inputModel . updateCmdLine ( cmdLineUpdate ) ;
}
2023-03-23 18:00:45 +01:00
@boundMethod
2023-03-23 23:44:19 +01:00
controlP() {
2023-03-23 18:00:45 +01:00
let inputModel = GlobalModel . inputModel ;
if ( ! inputModel . isHistoryLoaded ( ) ) {
this . lastHistoryUpDown = true ;
inputModel . loadHistory ( false , 1 , "screen" ) ;
return ;
}
inputModel . moveHistorySelection ( 1 ) ;
this . lastHistoryUpDown = true ;
}
@boundMethod
2023-03-23 23:44:19 +01:00
controlN() {
2023-03-23 18:00:45 +01:00
let inputModel = GlobalModel . inputModel ;
inputModel . moveHistorySelection ( - 1 ) ;
this . lastHistoryUpDown = true ;
}
2023-03-18 00:21:43 +01:00
@boundMethod
controlW() {
if ( this . mainInputRef . current == null ) {
return ;
}
let selStart = this . mainInputRef . current . selectionStart ;
let value = this . mainInputRef . current . value ;
if ( selStart > value . length ) {
return ;
}
let cutSpot = selStart - 1 ;
let initial = true ;
for ( ; cutSpot >= 0 ; cutSpot -- ) {
let ch = value [ cutSpot ] ;
console . log ( cutSpot , "[" + ch + "]" ) ;
if ( ch == " " && initial ) {
continue ;
}
initial = false ;
if ( ch == " " ) {
cutSpot ++ ;
break ;
}
}
let cutValue = value . slice ( cutSpot , selStart ) ;
let prevValue = value . slice ( 0 , cutSpot ) ;
let restValue = value . slice ( selStart ) ;
let cmdLineUpdate = { cmdline : prevValue + restValue , cursorpos : prevValue.length } ;
console . log ( "ss" , selStart , value , "prev[" + prevValue + "]" , "cut[" + cutValue + "]" , "rest[" + restValue + "]" ) ;
console . log ( " " , cmdLineUpdate ) ;
navigator . clipboard . writeText ( cutValue ) ;
GlobalModel . inputModel . updateCmdLine ( cmdLineUpdate ) ;
}
2023-03-08 05:40:30 +01:00
@boundMethod
controlY() {
if ( this . mainInputRef . current == null ) {
return ;
}
let pastePromise = navigator . clipboard . readText ( ) ;
pastePromise . then ( ( clipText ) = > {
clipText = clipText ? ? "" ;
let selStart = this . mainInputRef . current . selectionStart ;
let selEnd = this . mainInputRef . current . selectionEnd ;
let value = this . mainInputRef . current . value ;
if ( selStart > value . length || selEnd > value . length ) {
return ;
}
let newValue = value . substr ( 0 , selStart ) + clipText + value . substr ( selEnd ) ;
let cmdLineUpdate = { cmdline : newValue , cursorpos : selStart + clipText . length } ;
GlobalModel . inputModel . updateCmdLine ( cmdLineUpdate ) ;
} ) ;
}
2022-08-31 08:12:37 +02:00
@boundMethod
handleHistoryInput ( e : any ) {
let inputModel = GlobalModel . inputModel ;
mobx . action ( ( ) = > {
2022-08-31 09:02:16 +02:00
let opts = mobx . toJS ( inputModel . historyQueryOpts . get ( ) ) ;
opts . queryStr = e . target . value ;
inputModel . setHistoryQueryOpts ( opts ) ;
2022-08-31 08:12:37 +02:00
} ) ( ) ;
}
@boundMethod
handleMainFocus ( e : any ) {
let inputModel = GlobalModel . inputModel ;
if ( inputModel . historyShow . get ( ) ) {
e . preventDefault ( ) ;
2022-10-11 22:25:23 +02:00
if ( this . historyInputRef . current != null ) {
this . historyInputRef . current . focus ( ) ;
}
2022-10-11 08:44:04 +02:00
return ;
2022-08-31 08:12:37 +02:00
}
2022-10-11 08:44:04 +02:00
inputModel . setPhysicalInputFocused ( true ) ;
2022-10-06 23:00:24 +02:00
}
@boundMethod
handleMainBlur ( e : any ) {
2022-10-11 08:44:04 +02:00
if ( document . activeElement == this . mainInputRef . current ) {
return ;
}
2022-10-06 23:00:24 +02:00
GlobalModel . inputModel . setPhysicalInputFocused ( false ) ;
2022-08-31 08:12:37 +02:00
}
@boundMethod
handleHistoryFocus ( e : any ) {
let inputModel = GlobalModel . inputModel ;
if ( ! inputModel . historyShow . get ( ) ) {
e . preventDefault ( ) ;
2022-10-11 22:25:23 +02:00
if ( this . mainInputRef . current != null ) {
this . mainInputRef . current . focus ( ) ;
}
2022-10-11 08:44:04 +02:00
return ;
2022-08-31 08:12:37 +02:00
}
2022-10-11 08:44:04 +02:00
inputModel . setPhysicalInputFocused ( true ) ;
2022-10-06 23:00:24 +02:00
}
@boundMethod
handleHistoryBlur ( e : any ) {
2022-10-11 08:44:04 +02:00
if ( document . activeElement == this . historyInputRef . current ) {
return ;
}
2022-10-06 23:00:24 +02:00
GlobalModel . inputModel . setPhysicalInputFocused ( false ) ;
2022-08-31 08:12:37 +02:00
}
2022-08-25 04:00:03 +02:00
render() {
let model = GlobalModel ;
let inputModel = model . inputModel ;
let curLine = inputModel . getCurLine ( ) ;
2022-11-11 03:52:38 +01:00
let fcp = inputModel . forceCursorPos . get ( ) ; // for reaction
2022-08-25 04:00:03 +02:00
let numLines = curLine . split ( "\n" ) . length ;
let displayLines = numLines ;
if ( displayLines > 5 ) {
displayLines = 5 ;
}
2022-08-31 08:12:37 +02:00
let disabled = inputModel . historyShow . get ( ) ;
2022-08-31 21:00:53 +02:00
if ( disabled ) {
displayLines = 1 ;
}
2023-03-13 20:09:17 +01:00
let activeScreen = GlobalModel . getActiveScreen ( ) ;
if ( activeScreen != null ) {
activeScreen . focusType . get ( ) ; // for reaction
2022-10-11 08:44:04 +02:00
}
2023-04-04 08:17:15 +02:00
let computedHeight = ( displayLines * 24 ) + 14 ;
2022-08-25 04:00:03 +02:00
return (
2023-02-24 02:51:59 +01:00
< div className = "control cmd-input-control is-expanded" ref = { this . controlRef } >
2023-04-04 08:17:15 +02:00
< textarea ref = { this . mainInputRef } spellCheck = "false" autoComplete = "off" autoCorrect = "off" id = "main-cmd-input" onFocus = { this . handleMainFocus } onBlur = { this . handleMainBlur } style = { { height : computedHeight , minHeight : computedHeight } } value = { curLine } onKeyDown = { this . onKeyDown } onChange = { this . onChange } className = { cn ( "textarea" , { "display-disabled" : disabled } ) } > < / textarea >
2023-03-18 00:21:43 +01:00
< input ref = { this . historyInputRef } spellCheck = "false" autoComplete = "off" autoCorrect = "off" className = "history-input" type = "text" onFocus = { this . handleHistoryFocus } onKeyDown = { this . onHistoryKeyDown } onChange = { this . handleHistoryInput } value = { inputModel . historyQueryOpts . get ( ) . queryStr } / >
2022-08-31 08:12:37 +02:00
< / div >
2022-08-25 04:00:03 +02:00
) ;
}
}
2022-09-23 06:20:37 +02:00
@mobxReact . observer
class InfoMsg extends React . Component < { } , { } > {
getAfterSlash ( s : string ) : string {
if ( s . startsWith ( "^/" ) ) {
return s . substr ( 1 ) ;
}
let slashIdx = s . lastIndexOf ( "/" ) ;
if ( slashIdx == s . length - 1 ) {
slashIdx = s . lastIndexOf ( "/" , slashIdx - 1 ) ;
}
if ( slashIdx == - 1 ) {
return s ;
}
return s . substr ( slashIdx + 1 ) ;
2022-09-22 08:31:03 +02:00
}
2023-02-03 23:26:46 +01:00
hasSpace ( s : string ) : boolean {
return s . indexOf ( " " ) != - 1 ;
}
handleCompClick ( s : string ) : void {
// TODO -> complete to this completion
}
2022-09-15 02:14:27 +02:00
render() {
let model = GlobalModel ;
let inputModel = model . inputModel ;
let infoMsg = inputModel . infoMsg . get ( ) ;
let infoShow = inputModel . infoShow . get ( ) ;
let line : string = null ;
let istr : string = null ;
let idx : number = 0 ;
2022-09-30 23:57:23 +02:00
let titleStr = null ;
2022-10-04 04:05:52 +02:00
let remoteEditKey = "inforemoteedit" ;
2022-09-30 23:57:23 +02:00
if ( infoMsg != null ) {
titleStr = infoMsg . infotitle ;
}
2023-03-31 03:14:52 +02:00
let activeScreen = model . getActiveScreen ( ) ;
2022-09-15 02:14:27 +02:00
return (
< div className = "cmd-input-info" style = { { display : ( infoShow ? "block" : "none" ) } } >
< If condition = { infoMsg && infoMsg . infotitle != null } >
2022-09-23 06:20:37 +02:00
< div key = "infotitle" className = "info-title" >
2022-09-30 23:57:23 +02:00
{ titleStr }
2022-09-15 02:14:27 +02:00
< / div >
< / If >
< If condition = { infoMsg && infoMsg . infomsg != null } >
2022-09-23 06:20:37 +02:00
< div key = "infomsg" className = "info-msg" >
2023-03-31 03:14:52 +02:00
< If condition = { infoMsg . infomsghtml } >
< span dangerouslySetInnerHTML = { { __html : infoMsg.infomsg } } / >
< / If >
< If condition = { ! infoMsg . infomsghtml } >
{ infoMsg . infomsg }
< / If >
< / div >
< / If >
< If condition = { infoMsg && infoMsg . websharelink && activeScreen != null } >
< div key = "infomsg" className = "info-msg" >
2023-03-31 22:26:38 +02:00
started sharing screen at < a target = "_blank" href = { makeExternLink ( activeScreen . getWebShareUrl ( ) ) } > [ link ] < / a >
2022-09-15 02:14:27 +02:00
< / div >
< / If >
< If condition = { infoMsg && infoMsg . infolines != null } >
2022-09-23 06:20:37 +02:00
< div key = "infolines" className = "info-lines" >
2022-09-15 02:14:27 +02:00
< For index = "idx" each = "line" of = { infoMsg . infolines } >
< div key = { idx } > { line == "" ? " " : line } < / div >
< / For >
< / div >
< / If >
< If condition = { infoMsg && infoMsg . infocomps != null && infoMsg . infocomps . length > 0 } >
2022-09-23 06:20:37 +02:00
< div key = "infocomps" className = "info-comps" >
2022-09-15 02:14:27 +02:00
< For each = "istr" index = "idx" of = { infoMsg . infocomps } >
2023-02-03 23:26:46 +01:00
< div onClick = { ( ) = > this . handleCompClick ( istr ) } key = { idx } className = { cn ( "info-comp" , { "has-space" : this . hasSpace ( istr ) } , { "metacmd-comp" : istr . startsWith ( "^" ) } ) } >
2022-09-15 02:14:27 +02:00
{ this . getAfterSlash ( istr ) }
< / div >
< / For >
< If condition = { infoMsg . infocompsmore } >
2023-02-03 23:26:46 +01:00
< div key = "more" className = "info-comp no-select" >
2022-09-15 02:14:27 +02:00
. . .
< / div >
< / If >
< / div >
< / If >
< If condition = { infoMsg && infoMsg . infoerror != null } >
2022-09-23 06:20:37 +02:00
< div key = "infoerror" className = "info-error" >
2022-09-15 02:14:27 +02:00
[ error ] { infoMsg . infoerror }
< / div >
< / If >
< / div >
) ;
}
}
2022-08-31 00:25:51 +02:00
@mobxReact . observer
class HistoryInfo extends React . Component < { } , { } > {
2022-08-31 02:05:35 +02:00
lastClickHNum : string = null ;
lastClickTs : number = 0 ;
2022-08-31 08:12:37 +02:00
containingText : mobx.IObservableValue < string > = mobx . observable . box ( "" ) ;
2022-08-31 02:05:35 +02:00
2022-08-31 00:25:51 +02:00
componentDidMount() {
let inputModel = GlobalModel . inputModel ;
2022-08-31 08:12:37 +02:00
let hitem = inputModel . getHistorySelectedItem ( ) ;
if ( hitem == null ) {
hitem = inputModel . getFirstHistoryItem ( ) ;
}
if ( hitem != null ) {
inputModel . scrollHistoryItemIntoView ( hitem . historynum ) ;
2022-08-31 00:25:51 +02:00
}
}
2022-08-31 02:05:35 +02:00
@boundMethod
handleItemClick ( hitem : HistoryItem ) {
let inputModel = GlobalModel . inputModel ;
2022-08-31 08:12:37 +02:00
let selItem = inputModel . getHistorySelectedItem ( ) ;
if ( this . lastClickHNum == hitem . historynum && selItem != null && selItem . historynum == hitem . historynum ) {
2022-08-31 02:05:35 +02:00
inputModel . grabSelectedHistoryItem ( ) ;
return ;
}
2022-08-31 08:12:37 +02:00
inputModel . giveFocus ( ) ;
2022-08-31 02:05:35 +02:00
inputModel . setHistorySelectionNum ( hitem . historynum ) ;
let now = Date . now ( ) ;
this . lastClickHNum = hitem . historynum ;
this . lastClickTs = now ;
setTimeout ( ( ) = > {
if ( this . lastClickTs == now ) {
this . lastClickHNum = null ;
this . lastClickTs = 0 ;
}
} , 3000 ) ;
}
2022-08-31 21:00:53 +02:00
renderRemote ( hitem : HistoryItem ) : any {
if ( hitem . remote == null || isBlank ( hitem . remote . remoteid ) ) {
return sprintf ( "%-15s " , "" )
}
let r = GlobalModel . getRemote ( hitem . remote . remoteid ) ;
if ( r == null ) {
return sprintf ( "%-15s " , "???" )
}
let rname = "" ;
if ( ! isBlank ( r . remotealias ) ) {
rname = r . remotealias ;
}
else {
rname = r . remotecanonicalname ;
}
if ( ! isBlank ( hitem . remote . name ) ) {
rname = rname + ":" + hitem . remote . name ;
}
2023-03-15 19:14:28 +01:00
let rtn = sprintf ( "%-15s " , "[" + truncateWithTDots ( rname , 13 ) + "]" )
2022-08-31 21:00:53 +02:00
return rtn ;
}
2023-03-15 19:14:28 +01:00
renderHInfoText ( hitem : HistoryItem , opts : HistoryQueryOpts , isSelected : boolean , snames : Record < string , string > , scrNames : Record < string , string > ) : string {
let remoteStr = "" ;
if ( ! opts . limitRemote ) {
remoteStr = this . renderRemote ( hitem ) ;
}
let selectedStr = ( isSelected ? "*" : " " ) ;
let lineNumStr = ( hitem . linenum > 0 ? "(" + hitem . linenum + ")" : "" ) ;
if ( isBlank ( opts . queryType ) || opts . queryType == "screen" ) {
return selectedStr + sprintf ( "%7s" , lineNumStr ) + " " + remoteStr ;
}
if ( opts . queryType == "session" ) {
let screenStr = "" ;
if ( ! isBlank ( hitem . screenid ) ) {
let scrName = scrNames [ hitem . screenid ] ;
if ( scrName != null ) {
screenStr = "[" + truncateWithTDots ( scrName , 15 ) + "]" ;
}
}
return selectedStr + sprintf ( "%17s" , screenStr ) + sprintf ( "%7s" , lineNumStr ) + " " + remoteStr ;
}
2022-08-31 22:29:59 +02:00
if ( opts . queryType == "global" ) {
2023-03-15 19:14:28 +01:00
let sessionStr = "" ;
2022-08-31 22:29:59 +02:00
if ( ! isBlank ( hitem . sessionid ) ) {
2023-03-15 19:14:28 +01:00
let sessionName = snames [ hitem . sessionid ] ;
if ( sessionName != null ) {
sessionStr = "#" + truncateWithTDots ( sessionName , 15 ) ;
}
}
let screenStr = "" ;
if ( ! isBlank ( hitem . screenid ) ) {
let scrName = scrNames [ hitem . screenid ] ;
if ( scrName != null ) {
screenStr = "[" + truncateWithTDots ( scrName , 13 ) + "]" ;
2022-08-31 22:29:59 +02:00
}
}
2023-03-15 19:14:28 +01:00
let ssStr = sessionStr + screenStr ;
return selectedStr + sprintf ( "%15s " , sessionStr ) + " " + sprintf ( "%15s" , screenStr ) + sprintf ( "%7s" , lineNumStr ) + " " + remoteStr ;
2022-08-31 22:29:59 +02:00
}
2023-03-15 19:14:28 +01:00
return "-" ;
}
renderHItem ( hitem : HistoryItem , opts : HistoryQueryOpts , isSelected : boolean , snames : Record < string , string > , scrNames : Record < string , string > ) : any {
let lines = hitem . cmdstr . split ( "\n" ) ;
let line : string = "" ;
let idx = 0 ;
let infoText = this . renderHInfoText ( hitem , opts , isSelected , snames , scrNames ) ;
let infoTextSpacer = sprintf ( "%" + infoText . length + "s" , "" ) ;
2022-08-31 00:25:51 +02:00
return (
2022-08-31 09:02:16 +02:00
< div key = { hitem . historynum } className = { cn ( "history-item" , { "is-selected" : isSelected } , { "history-haderror" : hitem . haderror } , "hnum-" + hitem . historynum ) } onClick = { ( ) = > this . handleItemClick ( hitem ) } >
2023-03-15 19:14:28 +01:00
< div className = "history-line" > { infoText } { lines [ 0 ] } < / div >
2022-08-31 22:29:59 +02:00
< For each = "line" index = "idx" of = { lines . slice ( 1 ) } >
2023-03-15 19:14:28 +01:00
< div key = { idx } className = "history-line" > { infoTextSpacer } { line } < / div >
2022-08-31 00:25:51 +02:00
< / For >
< / div >
) ;
}
2022-08-31 02:05:35 +02:00
@boundMethod
handleClose() {
GlobalModel . inputModel . toggleInfoMsg ( ) ;
}
2022-08-31 08:12:37 +02:00
2022-08-31 00:25:51 +02:00
render() {
let inputModel = GlobalModel . inputModel ;
let idx : number = 0 ;
2022-08-31 08:12:37 +02:00
let selItem = inputModel . getHistorySelectedItem ( ) ;
2022-08-31 02:05:35 +02:00
let hitems = inputModel . getFilteredHistoryItems ( ) ;
2022-08-31 00:25:51 +02:00
hitems = hitems . slice ( ) . reverse ( ) ;
2022-08-31 02:05:35 +02:00
let hitem : HistoryItem = null ;
2022-08-31 09:02:16 +02:00
let opts = inputModel . historyQueryOpts . get ( ) ;
2023-03-15 19:14:28 +01:00
let snames : Record < string , string > = { } ;
let scrNames : Record < string , string > = { } ;
if ( opts . queryType == "global" ) {
scrNames = GlobalModel . getScreenNames ( ) ;
snames = GlobalModel . getSessionNames ( ) ;
}
else if ( opts . queryType == "session" ) {
scrNames = GlobalModel . getScreenNames ( ) ;
}
2022-08-31 00:25:51 +02:00
return (
< div className = "cmd-history" >
< div className = "history-title" >
2022-08-31 21:00:53 +02:00
< div > history < / div >
< div className = "spacer" > < / div >
2022-08-31 22:29:59 +02:00
< div className = "history-opt" > [ for { opts . queryType } & # x2318 ; S ] < / div >
2022-08-31 21:00:53 +02:00
< div className = "spacer" > < / div >
< div className = "history-opt" > [ containing '{opts.queryStr}' ] < / div >
< div className = "spacer" > < / div >
< div className = "history-opt" > [ { opts . limitRemote ? "this" : "any" } remote & # x2318 ; R ] < / div >
< div className = "grow-spacer" > < / div >
< div className = "history-clickable-opt" onClick = { this . handleClose } > ( ESC ) < / div >
< div className = "spacer" > < / div >
2022-08-31 00:25:51 +02:00
< / div >
2022-08-31 22:29:59 +02:00
< div className = { cn ( "history-items" , { "show-remotes" : ! opts . limitRemote } , { "show-sessions" : opts . queryType == "global" } ) } >
2022-08-31 00:25:51 +02:00
< If condition = { hitems . length == 0 } >
[ no history ]
< / If >
< If condition = { hitems . length > 0 } >
< For each = "hitem" index = "idx" of = { hitems } >
2023-03-15 19:14:28 +01:00
{ this . renderHItem ( hitem , opts , ( hitem == selItem ) , snames , scrNames ) }
2022-08-31 00:25:51 +02:00
< / For >
< / If >
< / div >
< / div >
) ;
}
}
2022-08-25 04:00:03 +02:00
@mobxReact . observer
class CmdInput extends React . Component < { } , { } > {
2022-12-27 19:58:11 +01:00
cmdInputRef : React.RefObject < any > = React . createRef ( ) ;
2022-09-17 01:37:54 +02:00
@boundMethod
onInfoToggle ( ) : void {
GlobalModel . inputModel . toggleInfoMsg ( ) ;
return ;
}
2022-12-27 19:58:11 +01:00
componentDidMount() {
2023-02-24 02:51:59 +01:00
this . updateCmdInputHeight ( ) ;
2022-12-27 19:58:11 +01:00
}
2023-02-24 02:51:59 +01:00
updateCmdInputHeight() {
2022-12-27 19:58:11 +01:00
let elem = this . cmdInputRef . current ;
if ( elem == null ) {
return ;
}
let height = elem . offsetHeight ;
2023-02-24 02:51:59 +01:00
if ( height == GlobalModel . inputModel . cmdInputHeight ) {
return ;
}
2022-12-27 19:58:11 +01:00
mobx . action ( ( ) = > {
GlobalModel . inputModel . cmdInputHeight . set ( height ) ;
} ) ( ) ;
}
2023-02-24 02:51:59 +01:00
componentDidUpdate ( prevProps , prevState , snapshot : { } ) : void {
this . updateCmdInputHeight ( ) ;
}
@boundMethod
handleInnerHeightUpdate ( ) : void {
this . updateCmdInputHeight ( ) ;
}
2023-03-14 05:56:29 +01:00
@boundMethod
clickFocusInputHint ( ) : void {
GlobalModel . inputModel . giveFocus ( ) ;
}
@boundMethod
2023-03-15 05:15:26 +01:00
clickHistoryHint ( e : any ) : void {
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
2023-03-14 05:56:29 +01:00
let inputModel = GlobalModel . inputModel ;
if ( inputModel . historyShow . get ( ) ) {
inputModel . resetHistory ( ) ;
}
else {
inputModel . openHistory ( ) ;
}
}
2023-03-27 21:32:26 +02:00
@boundMethod
clickConnectRemote ( remoteId : string ) : void {
GlobalCommandRunner . connectRemote ( remoteId ) ;
}
2022-09-17 01:37:54 +02:00
2022-06-08 02:25:35 +02:00
render() {
2022-08-11 03:35:18 +02:00
let model = GlobalModel ;
2022-08-30 21:22:42 +02:00
let inputModel = model . inputModel ;
2023-03-13 20:09:17 +01:00
let screen = GlobalModel . getActiveScreen ( ) ;
2022-08-11 03:35:18 +02:00
let ri : RemoteInstanceType = null ;
2022-08-24 22:19:59 +02:00
let rptr : RemotePtrType = null ;
2023-03-13 20:09:17 +01:00
if ( screen != null ) {
ri = screen . getCurRemoteInstance ( ) ;
rptr = screen . curRemote . get ( ) ;
2022-08-11 03:35:18 +02:00
}
let remote : RemoteType = null ;
2022-11-29 03:08:19 +01:00
let remoteState : FeStateType = null ;
2022-08-11 03:35:18 +02:00
if ( ri != null ) {
remote = GlobalModel . getRemote ( ri . remoteid ) ;
2022-11-29 03:08:19 +01:00
remoteState = ri . festate ;
2022-08-11 03:35:18 +02:00
}
2022-08-30 21:22:42 +02:00
let infoShow = inputModel . infoShow . get ( ) ;
let historyShow = ! infoShow && inputModel . historyShow . get ( ) ;
2022-09-23 06:20:37 +02:00
let infoMsg = inputModel . infoMsg . get ( ) ;
let hasInfo = ( infoMsg != null ) ;
2022-10-07 00:17:48 +02:00
let focusVal = inputModel . physicalInputFocused . get ( ) ;
2022-10-23 08:54:46 +02:00
let inputMode : string = inputModel . inputMode . get ( ) ;
2022-06-08 02:25:35 +02:00
return (
2023-04-04 06:33:03 +02:00
< div ref = { this . cmdInputRef } className = { cn ( "cmd-input has-background-black" , { "has-info" : infoShow } , { "has-history" : historyShow } ) } >
2022-10-07 00:17:48 +02:00
< div key = "focus" className = { cn ( "focus-indicator" , { "active" : focusVal } ) } / >
2022-10-04 22:53:04 +02:00
< div key = "minmax" onClick = { this . onInfoToggle } className = "input-minmax-control" >
2022-09-17 01:37:54 +02:00
< If condition = { infoShow || historyShow } >
2023-02-28 03:01:05 +01:00
< i className = "fa-sharp fa-solid fa-chevron-down" / >
2022-09-17 01:37:54 +02:00
< / If >
< If condition = { ! ( infoShow || historyShow ) && hasInfo } >
2023-02-28 03:01:05 +01:00
< i className = "fa-sharp fa-solid fa-chevron-up" / >
2022-09-17 01:37:54 +02:00
< / If >
< / div >
2022-08-31 00:25:51 +02:00
< If condition = { historyShow } >
2022-08-31 21:00:53 +02:00
< div className = "cmd-input-grow-spacer" > < / div >
2022-08-31 00:25:51 +02:00
< HistoryInfo / >
< / If >
2022-10-04 22:53:04 +02:00
< InfoMsg key = "infomsg" / >
2023-03-27 21:32:26 +02:00
< If condition = { remote && remote . status != "connected" } >
< div className = "remote-status-warning" >
WARNING : & nbsp ; < span className = "remote-name" > [ { GlobalModel . resolveRemoteIdToFullRef ( remote . remoteid ) } ] < / span > & nbsp ; is { remote . status }
< If condition = { remote . status != "connecting" } > < div className = "button is-prompt-green is-outlined is-small" onClick = { ( ) = > this . clickConnectRemote ( remote . remoteid ) } > connect now < / div > < / If >
< / div >
< / If >
2022-10-04 22:53:04 +02:00
< div key = "prompt" className = "cmd-input-context" >
2022-06-08 02:25:35 +02:00
< div className = "has-text-white" >
2022-11-29 03:08:19 +01:00
< Prompt rptr = { rptr } festate = { remoteState } / >
2022-06-08 02:25:35 +02:00
< / div >
< / div >
2022-10-23 08:54:46 +02:00
< div key = "input" className = { cn ( "cmd-input-field field has-addons" , ( inputMode != null ? "inputmode-" + inputMode : null ) ) } >
< If condition = { inputMode != null } >
< div className = "control cmd-quick-context" >
< div className = "button is-static" > { inputMode } < / div >
< / div >
< / If >
2023-02-24 02:51:59 +01:00
< TextAreaInput onHeightChange = { this . handleInnerHeightUpdate } / >
2022-06-08 02:25:35 +02:00
< div className = "control cmd-exec" >
2023-03-14 05:56:29 +01:00
< div onClick = { GlobalModel . inputModel . uiSubmitCommand } className = "button" title = "Run Command" >
2022-06-08 02:25:35 +02:00
< span className = "icon" >
2023-02-28 03:01:05 +01:00
< i className = "fa-sharp fa-solid fa-rocket" / >
2022-06-08 02:25:35 +02:00
< / span >
< / div >
< / div >
2023-03-14 07:36:27 +01:00
< div className = "cmd-hints" >
< If condition = { ! focusVal } > < div onClick = { this . clickFocusInputHint } className = "hint-item color-white" > focus input ( { renderCmdText ( "I" ) } ) < / div > < / If >
2023-03-15 05:15:26 +01:00
< If condition = { focusVal } > < div onMouseDown = { this . clickHistoryHint } className = "hint-item color-green" > < i className = { cn ( "fa-sharp fa-solid" , ( historyShow ? "fa-angle-down" : "fa-angle-up" ) ) } / > { historyShow ? "close history (esc)" : "show history (ctrl-r)" } < / div > < / If >
2023-03-14 05:56:29 +01:00
< / div >
2022-06-08 02:25:35 +02:00
< / div >
< / div >
) ;
}
}
2023-03-13 20:09:17 +01:00
// screen is not null
2022-10-08 03:25:47 +02:00
@mobxReact . observer
2023-03-13 20:09:17 +01:00
class ScreenWindowView extends React . Component < { screen : Screen } , { } > {
2022-10-08 03:25:47 +02:00
rszObs : any ;
2022-10-07 20:32:58 +02:00
windowViewRef : React.RefObject < any > ;
2022-06-18 02:54:14 +02:00
2022-11-23 07:57:35 +01:00
width : mobx.IObservableValue < number > = mobx . observable . box ( 0 , { name : "sw-view-width" } ) ;
2022-11-23 23:45:20 +01:00
height : mobx.IObservableValue < number > = mobx . observable . box ( 0 , { name : "sw-view-height" } ) ;
setSize_debounced : ( width : number , height : number ) = > void ;
2022-09-22 02:20:16 +02:00
2023-02-28 00:52:55 +01:00
renderMode : OV < RenderModeType > = mobx . observable . box ( "normal" , { name : "renderMode" } ) ;
2023-03-25 20:55:44 +01:00
shareCopied : OV < boolean > = mobx . observable . box ( false , { name : "sw-shareCopied" } ) ;
2023-02-28 00:52:55 +01:00
2022-09-04 08:39:50 +02:00
constructor ( props : any ) {
super ( props ) ;
2022-11-23 23:45:20 +01:00
this . setSize_debounced = debounce ( 1000 , this . setSize . bind ( this ) ) ;
2022-10-07 20:32:58 +02:00
this . windowViewRef = React . createRef ( ) ;
2022-09-22 02:20:16 +02:00
}
2022-11-23 23:45:20 +01:00
setSize ( width : number , height : number ) : void {
2023-03-13 20:09:17 +01:00
let { screen } = this . props ;
if ( screen == null ) {
2023-02-26 09:04:24 +01:00
return ;
}
2023-03-17 05:48:30 +01:00
if ( width == null || height == null || width == 0 || height == 0 ) {
return ;
}
2022-09-22 02:20:16 +02:00
mobx . action ( ( ) = > {
this . width . set ( width ) ;
2022-11-23 23:45:20 +01:00
this . height . set ( height ) ;
2023-03-17 05:48:30 +01:00
screen . screenSizeCallback ( { height : height , width : width } ) ;
2022-09-22 02:20:16 +02:00
} ) ( ) ;
2022-09-04 08:39:50 +02:00
}
2022-07-12 07:43:58 +02:00
componentDidMount() {
2022-10-07 20:32:58 +02:00
let wvElem = this . windowViewRef . current ;
2022-07-14 09:54:31 +02:00
if ( wvElem != null ) {
2022-09-22 02:20:16 +02:00
let width = wvElem . offsetWidth ;
2022-11-23 23:45:20 +01:00
let height = wvElem . offsetHeight ;
2023-04-04 22:25:05 +02:00
this . setSize ( width , height ) ;
2022-07-14 09:54:31 +02:00
this . rszObs = new ResizeObserver ( this . handleResize . bind ( this ) ) ;
this . rszObs . observe ( wvElem ) ;
2022-07-14 08:11:45 +02:00
}
2022-07-12 07:43:58 +02:00
}
componentWillUnmount() {
2022-07-14 09:54:31 +02:00
if ( this . rszObs ) {
this . rszObs . disconnect ( ) ;
}
}
handleResize ( entries : any ) {
if ( entries . length == 0 ) {
return ;
}
let entry = entries [ 0 ] ;
let width = entry . target . offsetWidth ;
2022-11-23 23:45:20 +01:00
let height = entry . target . offsetHeight ;
2023-03-22 01:08:31 +01:00
mobx . action ( ( ) = > {
this . setSize_debounced ( width , height ) ;
} ) ( ) ;
2022-07-12 07:43:58 +02:00
}
2023-03-15 04:09:59 +01:00
getScreenLines ( ) : ScreenLines {
2023-03-13 20:09:17 +01:00
let { screen } = this . props ;
2023-03-16 02:13:36 +01:00
let win = GlobalModel . getScreenLinesById ( screen . screenId ) ;
2022-07-15 03:41:49 +02:00
if ( win == null ) {
2023-03-16 02:13:36 +01:00
win = GlobalModel . loadScreenLines ( screen . screenId ) ;
2022-07-15 03:41:49 +02:00
}
return win ;
2022-07-12 07:43:58 +02:00
}
2022-07-13 08:29:39 +02:00
getWindowViewStyle ( ) : any {
2022-07-14 09:54:31 +02:00
return { position : "absolute" , width : "100%" , height : "100%" , overflowX : "hidden" } ;
}
2023-02-28 00:52:55 +01:00
@boundMethod
toggleRenderMode() {
let renderMode = this . renderMode . get ( ) ;
mobx . action ( ( ) = > {
this . renderMode . set ( renderMode == "normal" ? "collapsed" : "normal" ) ;
} ) ( ) ;
}
2023-02-24 08:36:35 +01:00
renderError ( message : string , fade : boolean ) {
2023-03-13 20:09:17 +01:00
let { screen } = this . props ;
2022-07-12 07:43:58 +02:00
return (
2023-03-15 00:38:26 +01:00
< div className = "window-view" style = { this . getWindowViewStyle ( ) } ref = { this . windowViewRef } data - screenid = { screen . screenId } >
2022-10-08 03:25:47 +02:00
< div key = "lines" className = "lines" > < / div >
2023-02-24 08:36:35 +01:00
< div key = "window-empty" className = { cn ( "window-empty" , { "should-fade" : fade } ) } >
2022-07-14 08:11:45 +02:00
< div > { message } < / div >
2022-07-12 07:43:58 +02:00
< / div >
< / div >
) ;
}
2022-10-08 03:25:47 +02:00
2023-03-25 20:55:44 +01:00
@boundMethod
copyShareLink ( ) : void {
2023-04-01 06:01:29 +02:00
let { screen } = this . props ;
let shareLink = screen . getWebShareUrl ( ) ;
if ( shareLink == null ) {
return ;
}
navigator . clipboard . writeText ( shareLink ) ;
2023-03-25 20:55:44 +01:00
mobx . action ( ( ) = > {
this . shareCopied . set ( true ) ;
} ) ( ) ;
setTimeout ( ( ) = > {
mobx . action ( ( ) = > {
this . shareCopied . set ( false ) ;
} ) ( ) ;
} , 600 )
}
2023-04-04 22:44:21 +02:00
@boundMethod
openScreenSettings ( ) : void {
let { screen } = this . props ;
mobx . action ( ( ) = > {
GlobalModel . screenSettingsModal . set ( { sessionId : screen.sessionId , screenId : screen.screenId } ) ;
} ) ( ) ;
}
2023-03-31 03:14:52 +02:00
@boundMethod
2023-03-31 03:33:37 +02:00
buildLineComponent ( lineProps : LineFactoryProps ) : JSX . Element {
2023-03-31 03:14:52 +02:00
let { screen } = this . props ;
let { line , . . . restProps } = lineProps ;
let realLine : LineType = ( line as LineType ) ;
return (
2023-03-31 03:33:37 +02:00
< Line key = { realLine . lineid } screen = { screen } line = { realLine } { ...restProps } / >
2023-03-31 03:14:52 +02:00
) ;
}
2022-06-08 02:25:35 +02:00
render() {
2023-03-13 20:09:17 +01:00
let { screen } = this . props ;
2023-03-15 04:09:59 +01:00
let win = this . getScreenLines ( ) ;
2022-07-15 03:41:49 +02:00
if ( win == null || ! win . loaded . get ( ) ) {
2023-02-24 08:36:35 +01:00
return this . renderError ( "..." , true ) ;
2022-07-02 22:32:25 +02:00
}
2022-07-15 03:41:49 +02:00
if ( win . loadError . get ( ) != null ) {
2023-02-24 08:36:35 +01:00
return this . renderError ( sprintf ( "(%s)" , win . loadError . get ( ) ) , false ) ;
2022-07-15 03:41:49 +02:00
}
2022-09-22 02:20:16 +02:00
if ( this . width . get ( ) == 0 ) {
2023-02-24 08:36:35 +01:00
return this . renderError ( "" , false ) ;
2022-07-14 09:54:31 +02:00
}
2023-02-26 23:16:42 +01:00
let cdata = GlobalModel . clientData . get ( ) ;
if ( cdata == null ) {
return this . renderError ( "loading client data" , true ) ;
}
2022-07-05 07:18:36 +02:00
let idx = 0 ;
2022-07-05 07:37:45 +02:00
let line : LineType = null ;
2023-03-13 20:09:17 +01:00
let session = GlobalModel . getSessionById ( screen . sessionId ) ;
let isActive = screen . isActive ( ) ;
let selectedLine = screen . getSelectedLine ( ) ;
2023-02-16 05:32:17 +01:00
let lines = win . getNonArchivedLines ( ) ;
2023-02-28 00:52:55 +01:00
let renderMode = this . renderMode . get ( ) ;
2022-06-08 02:25:35 +02:00
return (
2022-10-07 20:32:58 +02:00
< div className = "window-view" style = { this . getWindowViewStyle ( ) } ref = { this . windowViewRef } >
2023-03-15 00:38:26 +01:00
< div key = "rendermode-tag" className = { cn ( "rendermode-tag" , { "is-active" : isActive } ) } >
2023-02-28 00:52:55 +01:00
< div className = "render-mode" onClick = { this . toggleRenderMode } >
< If condition = { renderMode == "normal" } >
< i title = "collapse" className = "fa-sharp fa-solid fa-arrows-to-line" / >
< / If >
< If condition = { renderMode == "collapsed" } >
< i title = "expand" className = "fa-sharp fa-solid fa-arrows-from-line" / >
< / If >
< / div >
2022-07-14 08:11:45 +02:00
< / div >
2023-04-02 07:25:18 +02:00
< If condition = { screen . isWebShared ( ) } >
2023-03-25 20:55:44 +01:00
< div key = "share-tag" className = "share-tag" >
< If condition = { this . shareCopied . get ( ) } >
< div className = "copied-indicator" / >
< / If >
2023-04-04 22:44:21 +02:00
< div className = "share-tag-title" > < i title = "archived" className = "fa-sharp fa-solid fa-share-nodes" / > web shared < / div >
2023-04-01 06:01:29 +02:00
< div className = "share-tag-link" >
< div className = "button is-prompt-green is-outlined is-small" onClick = { this . copyShareLink } >
< span > copy link < / span >
< span className = "icon" >
< i className = "fa-sharp fa-solid fa-copy" / >
< / span >
< / div >
2023-04-04 22:44:21 +02:00
< div className = "button is-prompt-green is-outlined is-small" onClick = { this . openScreenSettings } >
< span > open settings < / span >
< span className = "icon" >
< i className = "fa-sharp fa-solid fa-cog" / >
< / span >
< / div >
2023-04-01 06:01:29 +02:00
< / div >
2023-03-25 20:55:44 +01:00
< / div >
< / If >
2023-02-16 05:32:17 +01:00
< If condition = { lines . length > 0 } >
2023-03-31 03:14:52 +02:00
< LinesView screen = { screen } width = { this . width . get ( ) } lines = { lines } renderMode = { renderMode } lineFactory = { this . buildLineComponent } / >
2022-10-08 03:25:47 +02:00
< / If >
2023-02-16 05:32:17 +01:00
< If condition = { lines . length == 0 } >
2022-07-14 08:11:45 +02:00
< div key = "window-empty" className = "window-empty" >
2023-03-15 00:38:26 +01:00
< div > < code > [ session = "{session.name.get()}" screen = "{screen.name.get()}" ] < / code > < / div >
2022-07-14 08:11:45 +02:00
< / div >
< / If >
2022-07-12 07:43:58 +02:00
< / div >
) ;
}
}
2022-07-13 08:29:39 +02:00
@mobxReact . observer
class ScreenView extends React . Component < { screen : Screen } , { } > {
render() {
let { screen } = this . props ;
2023-03-13 20:09:17 +01:00
if ( screen == null ) {
2022-07-13 08:29:39 +02:00
return (
< div className = "screen-view" >
2023-03-13 20:09:17 +01:00
( no screen found )
2022-07-13 08:29:39 +02:00
< / div >
) ;
}
2023-02-26 08:16:58 +01:00
let fontSize = GlobalModel . termFontSize . get ( ) ;
2022-07-13 08:29:39 +02:00
return (
2023-03-13 20:09:17 +01:00
< div className = "screen-view" data - screenid = { screen . screenId } >
2023-03-23 20:08:48 +01:00
< ScreenWindowView key = { screen . screenId + ":" + fontSize } screen = { screen } / >
2022-07-13 08:29:39 +02:00
< / div >
) ;
}
}
@mobxReact . observer
2022-07-14 08:11:45 +02:00
class ScreenTabs extends React . Component < { session : Session } , { } > {
2023-02-16 05:48:19 +01:00
tabsRef : React.RefObject < any > = React . createRef ( ) ;
lastActiveScreenId : string = null ;
2023-02-24 01:06:44 +01:00
scrolling : OV < boolean > = mobx . observable . box ( false , { name : "screentabs-scrolling" } ) ;
stopScrolling_debounced : ( ) = > void ;
constructor ( props : any ) {
super ( props ) ;
this . stopScrolling_debounced = debounce ( 1500 , this . stopScrolling . bind ( this ) ) ;
}
2023-02-16 05:48:19 +01:00
2022-07-14 08:11:45 +02:00
@boundMethod
handleNewScreen() {
let { session } = this . props ;
2022-08-31 02:05:35 +02:00
GlobalCommandRunner . createNewScreen ( ) ;
2022-07-14 08:11:45 +02:00
}
@boundMethod
handleSwitchScreen ( screenId : string ) {
let { session } = this . props ;
if ( session == null ) {
return ;
}
if ( session . activeScreenId . get ( ) == screenId ) {
return ;
}
let screen = session . getScreenById ( screenId ) ;
if ( screen == null ) {
return ;
}
2022-08-31 02:05:35 +02:00
GlobalCommandRunner . switchScreen ( screenId ) ;
2022-07-14 08:11:45 +02:00
}
2022-08-09 01:22:36 +02:00
2023-02-16 05:48:19 +01:00
componentDidMount ( ) : void {
this . componentDidUpdate ( ) ;
}
componentDidUpdate ( ) : void {
let { session } = this . props ;
let activeScreenId = session . activeScreenId . get ( ) ;
if ( activeScreenId != this . lastActiveScreenId && this . tabsRef . current ) {
let tabElem = this . tabsRef . current . querySelector ( sprintf ( ".screen-tab[data-screenid=\"%s\"]" , activeScreenId ) ) ;
if ( tabElem != null ) {
tabElem . scrollIntoView ( ) ;
}
}
this . lastActiveScreenId = activeScreenId ;
}
2023-02-24 01:06:44 +01:00
stopScrolling ( ) : void {
mobx . action ( ( ) = > {
this . scrolling . set ( false ) ;
} ) ( ) ;
}
@boundMethod
handleScroll() {
if ( ! this . scrolling . get ( ) ) {
mobx . action ( ( ) = > {
this . scrolling . set ( true ) ;
} ) ( ) ;
}
this . stopScrolling_debounced ( ) ;
}
2023-03-14 07:36:27 +01:00
@boundMethod
openScreenSettings ( e : any , screen : Screen ) : void {
e . preventDefault ( ) ;
2023-03-14 19:48:14 +01:00
e . stopPropagation ( ) ;
2023-03-14 07:36:27 +01:00
mobx . action ( ( ) = > {
GlobalModel . screenSettingsModal . set ( { sessionId : screen.sessionId , screenId : screen.screenId } ) ;
} ) ( ) ;
}
2022-07-13 08:29:39 +02:00
render() {
2022-07-14 08:11:45 +02:00
let { session } = this . props ;
2022-07-13 08:29:39 +02:00
if ( session == null ) {
return null ;
}
2022-07-14 08:11:45 +02:00
let screen : Screen = null ;
2022-07-15 03:41:49 +02:00
let index = 0 ;
2022-12-26 21:36:24 +01:00
let showingScreens = [ ] ;
let activeScreenId = session . activeScreenId . get ( ) ;
2023-03-13 20:09:17 +01:00
let screens = GlobalModel . getSessionScreens ( session . sessionId ) ;
for ( let screen of screens ) {
2022-12-26 21:36:24 +01:00
if ( ! screen . archived . get ( ) || activeScreenId == screen . screenId ) {
showingScreens . push ( screen ) ;
}
}
2023-03-15 05:15:26 +01:00
showingScreens . sort ( ( a , b ) = > {
let aidx = a . screenIdx . get ( ) ;
let bidx = b . screenIdx . get ( ) ;
if ( aidx < bidx ) {
return - 1 ;
}
if ( aidx > bidx ) {
return 1 ;
}
return 0 ;
} ) ;
2022-07-13 08:29:39 +02:00
return (
2023-03-14 07:36:27 +01:00
< div className = "screen-tabs-container" >
< div className = { cn ( "screen-tabs" , { "scrolling" : this . scrolling . get ( ) } ) } ref = { this . tabsRef } onScroll = { this . handleScroll } >
< For each = "screen" index = "index" of = { showingScreens } >
< div key = { screen . screenId } data - screenid = { screen . screenId } className = { cn ( "screen-tab" , { "is-active" : activeScreenId == screen . screenId , "is-archived" : screen . archived . get ( ) } , "color-" + screen . getTabColor ( ) ) } onClick = { ( ) = > this . handleSwitchScreen ( screen . screenId ) } onContextMenu = { ( event ) = > this . openScreenSettings ( event , screen ) } >
2023-03-25 20:55:44 +01:00
< If condition = { screen . archived . get ( ) } > < i title = "archived" className = "fa-sharp fa-solid fa-box-archive" / > < / If >
2023-04-02 07:25:18 +02:00
< If condition = { screen . isWebShared ( ) } > < i title = "archived" className = "fa-sharp fa-solid fa-share-nodes web-share-icon" / > < / If >
2023-03-25 20:55:44 +01:00
{ screen . name . get ( ) }
2023-03-14 07:36:27 +01:00
< If condition = { index + 1 <= 9 } >
< div className = "tab-index" > { renderCmdText ( String ( index + 1 ) ) } < / div >
< div onClick = { ( e ) = > this . openScreenSettings ( e , screen ) } title = "Settings" className = "tab-gear" > < i className = "fa-sharp fa-solid fa-gear" / > < / div >
< / If >
< If condition = { index + 1 > 9 } >
< div onClick = { ( e ) = > this . openScreenSettings ( e , screen ) } title = "Settings" className = "tab-gear" > < i className = "fa-sharp fa-solid fa-gear" / > < / div >
< / If >
< / div >
< / For >
< div key = "new-screen" className = "screen-tab new-screen" onClick = { this . handleNewScreen } >
< i className = "fa-sharp fa-solid fa-plus" / >
2022-07-14 08:11:45 +02:00
< / div >
2023-03-14 07:36:27 +01:00
< / div >
< div className = "cmd-hints" >
< div className = "hint-item color-green" > move left { renderCmdText ( "[" ) } < / div >
< div className = "hint-item color-green" > move right { renderCmdText ( "]" ) } < / div >
< div className = "hint-item color-green" > new tab { renderCmdText ( "T" ) } < / div >
2022-07-14 08:11:45 +02:00
< / div >
2022-07-13 08:29:39 +02:00
< / div >
) ;
}
}
2022-07-12 07:43:58 +02:00
@mobxReact . observer
class SessionView extends React . Component < { } , { } > {
render() {
let model = GlobalModel ;
let session = model . getActiveSession ( ) ;
if ( session == null ) {
return < div className = "session-view" > ( no active session ) < / div > ;
}
2022-07-13 08:29:39 +02:00
let activeScreen = session . getActiveScreen ( ) ;
2022-12-27 19:58:11 +01:00
let cmdInputHeight = model . inputModel . cmdInputHeight . get ( ) ;
if ( cmdInputHeight == 0 ) {
cmdInputHeight = 110 ;
}
2023-02-21 07:32:11 +01:00
let isHidden = ( GlobalModel . activeMainView . get ( ) != "session" ) ;
2022-07-12 07:43:58 +02:00
return (
2023-02-03 23:26:46 +01:00
< div className = { cn ( "session-view" , { "is-hidden" : isHidden } ) } data - sessionid = { session . sessionId } >
2022-07-13 08:29:39 +02:00
< ScreenView screen = { activeScreen } / >
2022-07-14 08:11:45 +02:00
< ScreenTabs session = { session } / >
2022-12-27 19:58:11 +01:00
< div style = { { height : cmdInputHeight } } > < / div >
2022-07-12 02:55:03 +02:00
< CmdInput / >
2022-06-08 02:25:35 +02:00
< / div >
) ;
}
}
2022-06-20 22:03:20 +02:00
@mobxReact . observer
class MainSideBar extends React . Component < { } , { } > {
collapsed : mobx.IObservableValue < boolean > = mobx . observable . box ( false ) ;
@boundMethod
toggleCollapsed() {
mobx . action ( ( ) = > {
this . collapsed . set ( ! this . collapsed . get ( ) ) ;
} ) ( ) ;
}
2022-07-08 22:23:00 +02:00
handleSessionClick ( sessionId : string ) {
2022-08-31 02:05:35 +02:00
GlobalCommandRunner . switchSession ( sessionId ) ;
2022-08-09 01:22:36 +02:00
}
handleNewSession() {
2022-08-31 02:05:35 +02:00
GlobalCommandRunner . createNewSession ( ) ;
2022-07-08 22:23:00 +02:00
}
2022-07-09 10:37:19 +02:00
2023-02-21 03:01:47 +01:00
handleNewSharedSession() {
2023-02-22 07:42:44 +01:00
GlobalCommandRunner . openSharedSession ( ) ;
2023-02-21 03:01:47 +01:00
}
2023-03-23 20:16:45 +01:00
clickLinks() {
mobx . action ( ( ) = > {
GlobalModel . showLinks . set ( ! GlobalModel . showLinks . get ( ) ) ;
} ) ( ) ;
}
2022-09-14 02:17:52 +02:00
remoteDisplayName ( remote : RemoteType ) : any {
if ( ! isBlank ( remote . remotealias ) ) {
return (
< >
< span > { remote . remotealias } < / span >
< span className = "small-text" > { remote . remotecanonicalname } < / span >
< / >
) ;
}
return ( < span > { remote . remotecanonicalname } < / span > ) ;
}
2022-09-14 22:02:33 +02:00
clickRemote ( remote : RemoteType ) {
GlobalCommandRunner . showRemote ( remote . remoteid ) ;
}
2022-09-22 07:42:51 +02:00
@boundMethod
handleAddRemote ( ) : void {
2022-09-30 23:57:23 +02:00
GlobalCommandRunner . openCreateRemote ( ) ;
2022-09-22 07:42:51 +02:00
}
2023-02-03 23:26:46 +01:00
@boundMethod
handleHistoryClick ( ) : void {
2023-03-02 09:33:10 +01:00
if ( GlobalModel . activeMainView . get ( ) == "history" ) {
mobx . action ( ( ) = > {
GlobalModel . activeMainView . set ( "session" ) ;
} ) ( ) ;
return ;
}
2023-03-06 22:57:28 +01:00
GlobalModel . historyViewModel . reSearch ( ) ;
2023-03-02 09:33:10 +01:00
}
@boundMethod
handlePlaybookClick ( ) : void {
console . log ( "playbook click" ) ;
return ;
2023-02-03 23:26:46 +01:00
}
2023-02-21 03:01:47 +01:00
@boundMethod
handleBookmarksClick ( ) : void {
2023-02-21 07:32:11 +01:00
if ( GlobalModel . activeMainView . get ( ) == "bookmarks" ) {
mobx . action ( ( ) = > {
GlobalModel . activeMainView . set ( "session" ) ;
} ) ( ) ;
return ;
}
GlobalCommandRunner . bookmarksView ( ) ;
2023-02-21 03:01:47 +01:00
}
2023-03-08 05:40:30 +01:00
@boundMethod
handleWelcomeClick ( ) : void {
mobx . action ( ( ) = > {
GlobalModel . welcomeModalOpen . set ( true ) ;
} ) ( ) ;
}
2023-03-23 20:08:48 +01:00
@boundMethod
handleSettingsClick ( ) : void {
mobx . action ( ( ) = > {
GlobalModel . clientSettingsModal . set ( true ) ;
} ) ( ) ;
}
2023-04-03 10:39:27 +02:00
@boundMethod
handleConnectionsClick ( ) : void {
2023-04-03 20:29:54 +02:00
GlobalModel . remotesModalModel . openModal ( ) ;
2023-04-03 10:39:27 +02:00
}
2023-03-14 19:48:14 +01:00
@boundMethod
openSessionSettings ( e : any , session : Session ) : void {
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
mobx . action ( ( ) = > {
GlobalModel . sessionSettingsModal . set ( session . sessionId ) ;
} ) ( ) ;
}
2022-06-20 22:03:20 +02:00
render() {
2022-07-11 23:43:18 +02:00
let model = GlobalModel ;
2022-07-13 23:16:47 +02:00
let activeSessionId = model . activeSessionId . get ( ) ;
2023-03-15 04:09:59 +01:00
let activeWindow = model . getScreenLinesForActiveScreen ( ) ;
2023-03-13 20:09:17 +01:00
let activeScreen = model . getActiveScreen ( ) ;
2022-09-30 23:57:23 +02:00
let activeRemoteId : string = null ;
2023-03-13 20:09:17 +01:00
if ( activeScreen != null ) {
let rptr = activeScreen . curRemote . get ( ) ;
2022-09-30 23:57:23 +02:00
if ( rptr != null && ! isBlank ( rptr . remoteid ) ) {
activeRemoteId = rptr . remoteid ;
}
}
2022-07-12 02:55:03 +02:00
let session : Session = null ;
2022-09-14 02:17:52 +02:00
let remotes = model . remotes ? ? [ ] ;
2022-08-17 22:06:47 +02:00
let remote : RemoteType = null ;
2022-08-27 02:28:56 +02:00
let idx : number = 0 ;
2022-09-22 07:17:04 +02:00
remotes = sortAndFilterRemotes ( remotes ) ;
2022-12-27 03:50:22 +01:00
let sessionList = [ ] ;
for ( let session of model . sessionList ) {
if ( ! session . archived . get ( ) || session . sessionId == activeSessionId ) {
sessionList . push ( session ) ;
}
}
2022-12-29 02:46:15 +01:00
let isCollapsed = this . collapsed . get ( ) ;
2023-02-21 07:32:11 +01:00
let mainView = GlobalModel . activeMainView . get ( ) ;
2023-03-02 09:33:10 +01:00
let activePlaybookId : string = null ;
2022-06-20 22:03:20 +02:00
return (
2023-02-03 23:26:46 +01:00
< div className = { cn ( "main-sidebar" , { "collapsed" : isCollapsed } , { "is-dev" : GlobalModel . isDev } ) } >
2023-03-20 08:28:49 +01:00
< div className = "logo-header" >
< h1 className = { cn ( "title" , "prompt-logo-small" , { "collapsed" : isCollapsed } , { "is-dev" : GlobalModel . isDev } ) } >
{ ( isCollapsed ? "[p]" : "[prompt]" ) }
< / h1 >
< / div >
2022-06-20 22:03:20 +02:00
< div className = "collapse-container" >
< div className = "arrow-container" onClick = { this . toggleCollapsed } >
2023-03-23 20:16:45 +01:00
< If condition = { ! isCollapsed } > < i className = "fa-sharp fa-solid fa-angle-left" / > < / If >
< If condition = { isCollapsed } > < i className = "fa-sharp fa-solid fa-angle-right" / > < / If >
2022-06-20 22:03:20 +02:00
< / div >
< / div >
< div className = "menu" >
< p className = "menu-label" >
2023-04-05 08:26:34 +02:00
Sessions
2022-06-20 22:03:20 +02:00
< / p >
2023-03-14 19:48:14 +01:00
< ul className = "menu-list session-menu-list" >
2022-07-12 02:55:03 +02:00
< If condition = { ! model . sessionListLoaded . get ( ) } >
2023-03-14 19:48:14 +01:00
< li className = "menu-loading-message" > < a > . . . < / a > < / li >
2022-07-11 23:43:18 +02:00
< / If >
2022-07-12 02:55:03 +02:00
< If condition = { model . sessionListLoaded . get ( ) } >
2022-12-27 03:50:22 +01:00
< For each = "session" index = "idx" of = { sessionList } >
2023-02-21 07:32:11 +01:00
< li key = { session . sessionId } > < a className = { cn ( { "is-active" : mainView == "session" && activeSessionId == session . sessionId } ) } onClick = { ( ) = > this . handleSessionClick ( session . sessionId ) } >
2022-12-27 03:50:22 +01:00
< If condition = { ! session . archived . get ( ) } >
2023-04-05 08:26:34 +02:00
< div className = "session-num" > < span className = "hotkey" > ^ ⌘ < / span > { idx + 1 } < / div >
2022-12-27 03:50:22 +01:00
< / If >
< If condition = { session . archived . get ( ) } >
2023-03-14 19:48:14 +01:00
< div className = "session-num" > < i title = "archived" className = "fa-sharp fa-solid fa-box-archive" / > < / div >
2022-12-27 03:50:22 +01:00
< / If >
2023-03-14 19:48:14 +01:00
< div >
{ session . name . get ( ) }
< / div >
< div className = "flex-spacer" / >
< div className = "session-gear" onClick = { ( e ) = > this . openSessionSettings ( e , session ) } >
< i className = "fa-sharp fa-solid fa-gear" / >
< / div >
2022-08-27 02:28:56 +02:00
< / a > < / li >
2022-07-11 23:43:18 +02:00
< / For >
2023-02-28 03:01:05 +01:00
< li className = "new-session" > < a onClick = { ( ) = > this . handleNewSession ( ) } > < i className = "fa-sharp fa-solid fa-plus" / > New Session < / a > < / li >
2022-07-11 23:43:18 +02:00
< / If >
2022-06-20 22:03:20 +02:00
< / ul >
2023-03-02 09:33:10 +01:00
< ul className = "menu-list" style = { { marginTop : 20 } } >
2023-03-14 03:54:41 +01:00
< li className = "menu-history" > < a onClick = { this . handleHistoryClick } className = { cn ( { "is-active" : ( mainView == "history" ) } ) } > < i className = "fa-sharp fa-solid fa-clock" / > HISTORY < span className = "hotkey" > & # x2318 ; H < / span > < / a > < / li >
2023-02-03 23:26:46 +01:00
< / ul >
2023-03-02 09:33:10 +01:00
< ul className = "menu-list" >
2023-03-14 03:54:41 +01:00
< li className = "menu-bookmarks" > < a onClick = { this . handleBookmarksClick } className = { cn ( { "is-active" : ( mainView == "bookmarks" ) } ) } > < i className = "fa-sharp fa-solid fa-bookmark" / > BOOKMARKS < span className = "hotkey" > & # x2318 ; B < / span > < / a > < / li >
2023-02-21 03:01:47 +01:00
< / ul >
2023-04-04 18:01:11 +02:00
< ul className = "menu-list" style = { { display : "none" } } >
< li className = "menu-websharing" > < a onClick = { this . handleBookmarksClick } className = { cn ( { "is-active" : ( mainView == "bookmarks" ) } ) } > < i className = "fa-sharp fa-solid fa-share-nodes" / > WEB SHARING < / a > < / li >
< / ul >
2023-03-07 00:51:50 +01:00
< p className = "menu-label display-none" >
2023-03-02 09:33:10 +01:00
Playbooks
< / p >
2023-03-07 00:51:50 +01:00
< ul className = "menu-list display-none" >
2023-03-02 09:33:10 +01:00
< li key = "default" > < a onClick = { this . handlePlaybookClick } > < i className = "fa-sharp fa-solid fa-file-lines" / > default < / a > < / li >
< li key = "prompt-dev" > < a onClick = { this . handlePlaybookClick } > < i className = "fa-sharp fa-solid fa-file-lines" / > prompt - dev < / a > < / li >
< / ul >
2022-06-20 22:03:20 +02:00
< div className = "spacer" > < / div >
2023-03-13 20:09:17 +01:00
< If condition = { GlobalModel . debugScreen . get ( ) && activeScreen != null } >
2022-10-11 23:57:22 +02:00
< div >
2023-03-13 20:09:17 +01:00
focus = { activeScreen . focusType . get ( ) } < br / >
sline = { activeScreen . getSelectedLine ( ) } < br / >
termfocus = { activeScreen . termLineNumFocus . get ( ) } < br / >
2022-10-11 23:57:22 +02:00
< / div >
< / If >
2023-03-15 05:24:35 +01:00
< ul className = "menu-list" style = { { display : "none" } } >
2023-03-08 05:40:30 +01:00
< li className = "menu-bookmarks" > < a onClick = { this . handleWelcomeClick } className = { cn ( { "is-active" : GlobalModel . welcomeModalOpen . get ( ) } ) } > < i className = "fa-sharp fa-solid fa-door-open" / > WELCOME < / a > < / li >
< / ul >
2023-03-23 20:08:48 +01:00
< ul className = "menu-list" >
2023-04-03 10:39:27 +02:00
< li className = "menu-settings" > < a onClick = { this . handleSettingsClick } > < i className = "fa-sharp fa-solid fa-cog" / > SETTINGS < / a > < / li >
< / ul >
2022-12-12 21:11:02 +01:00
< p className = "menu-label" >
2023-03-23 20:16:45 +01:00
< a onClick = { ( ) = > this . clickLinks ( ) } > LINKS < i className = { cn ( "fa-sharp fa-solid" , ( GlobalModel . showLinks . get ( ) ? "fa-angle-down" : "fa-angle-right" ) ) } / > < / a >
2022-12-12 21:11:02 +01:00
< / p >
2023-03-23 20:16:45 +01:00
< ul className = "menu-list" style = { { display : ( GlobalModel . showLinks . get ( ) ? null : "none" ) } } >
2022-12-12 21:11:02 +01:00
< li >
2023-02-28 03:01:05 +01:00
< a target = "_blank" href = "https://docs.getprompt.dev/releasenotes" > < i style = { { width : 20 } } className = "fa-sharp fa-solid fa-notes" / > release notes < / a >
< / li >
< li >
< a target = "_blank" href = "https://docs.getprompt.dev/" > < i style = { { width : 20 } } className = "fa-sharp fa-solid fa-book" / > documentation < / a >
2022-12-12 21:11:02 +01:00
< / li >
< li >
2023-02-27 21:22:45 +01:00
< a target = "_blank" href = "https://discord.gg/XfvZ334gwU" > < i style = { { width : 20 } } className = "fa-brands fa-discord" / > discord < / a >
2022-12-12 21:11:02 +01:00
< / li >
< / ul >
2022-06-20 22:03:20 +02:00
< p className = "menu-label" >
2023-04-04 18:01:11 +02:00
< a onClick = { this . handleConnectionsClick } > Connections < / a >
2022-06-20 22:03:20 +02:00
< / p >
2022-09-14 21:07:31 +02:00
< ul className = "menu-list remotes-menu-list" >
2022-08-17 22:06:47 +02:00
< For each = "remote" of = { remotes } >
2022-09-30 23:57:23 +02:00
< li key = { remote . remoteid } className = { cn ( "remote-menu-item" ) } > < a className = { cn ( { "is-active" : ( remote . remoteid == activeRemoteId ) } ) } onClick = { ( ) = > this . clickRemote ( remote ) } >
2022-10-01 02:23:28 +02:00
< RemoteStatusLight remote = { remote } / >
2022-09-14 02:17:52 +02:00
{ this . remoteDisplayName ( remote ) }
< / a > < / li >
2022-08-17 22:06:47 +02:00
< / For >
2022-09-22 07:42:51 +02:00
< li key = "add-remote" className = "add-remote" >
2023-02-28 03:01:05 +01:00
< a onClick = { ( ) = > this . handleAddRemote ( ) } > < i className = "fa-sharp fa-solid fa-plus" / > Add Connection < / a >
2022-09-22 07:42:51 +02:00
< / li >
2022-06-20 22:03:20 +02:00
< / ul >
< div className = "bottom-spacer" > < / div >
< / div >
< / div >
) ;
}
}
2022-08-18 09:39:06 +02:00
@mobxReact . observer
2022-10-28 23:17:45 +02:00
class DisconnectedModal extends React . Component < { } , { } > {
logRef : any = React . createRef ( ) ;
showLog : mobx.IObservableValue < boolean > = mobx . observable . box ( false )
2022-09-22 07:42:51 +02:00
2022-10-28 23:17:45 +02:00
@boundMethod
restartServer() {
2022-10-30 20:53:39 +01:00
GlobalModel . restartLocalServer ( ) ;
2022-09-22 07:42:51 +02:00
}
2022-08-18 09:39:06 +02:00
@boundMethod
2022-10-28 23:17:45 +02:00
tryReconnect() {
GlobalModel . ws . connectNow ( "manual" ) ;
}
componentDidMount() {
if ( this . logRef . current != null ) {
this . logRef . current . scrollTop = this . logRef . current . scrollHeight ;
}
}
componentDidUpdate() {
if ( this . logRef . current != null ) {
this . logRef . current . scrollTop = this . logRef . current . scrollHeight ;
}
2022-08-18 09:39:06 +02:00
}
2022-09-22 08:31:03 +02:00
@boundMethod
2022-10-28 23:17:45 +02:00
handleShowLog ( ) : void {
2022-09-22 08:31:03 +02:00
mobx . action ( ( ) = > {
2022-10-28 23:17:45 +02:00
this . showLog . set ( ! this . showLog . get ( ) ) ;
2022-09-22 08:31:03 +02:00
} ) ( ) ;
}
2022-08-18 09:39:06 +02:00
render() {
let model = GlobalModel ;
2022-10-28 23:17:45 +02:00
let logLine : string = null ;
let idx : number = 0 ;
2022-08-18 09:39:06 +02:00
return (
2023-03-19 22:59:21 +01:00
< div className = "prompt-modal disconnected-modal modal is-active" >
2022-10-28 23:17:45 +02:00
< div className = "modal-background" > < / div >
2023-03-19 22:59:21 +01:00
< div className = "modal-content" >
2022-08-18 09:39:06 +02:00
< div className = "message-header" >
2023-03-19 22:59:21 +01:00
< div className = "modal-title" > Prompt Client Disconnected < / div >
2022-08-18 09:39:06 +02:00
< / div >
2022-10-28 23:17:45 +02:00
< If condition = { this . showLog . get ( ) } >
2023-03-19 22:59:21 +01:00
< div className = "inner-content" >
2022-10-28 23:17:45 +02:00
< div className = "ws-log" ref = { this . logRef } >
< For each = "logLine" index = "idx" of = { GlobalModel . ws . wsLog } >
< div key = { idx } className = "ws-logline" > { logLine } < / div >
2022-08-18 09:39:06 +02:00
< / For >
2022-10-28 23:17:45 +02:00
< / div >
< / div >
< / If >
2023-03-19 22:59:21 +01:00
< footer >
2022-10-28 23:17:45 +02:00
< div className = "footer-text-link" style = { { marginLeft : 10 } } onClick = { this . handleShowLog } >
< If condition = { ! this . showLog . get ( ) } >
2023-02-28 03:01:05 +01:00
< i className = "fa-sharp fa-solid fa-plus" / > Show Log
2022-10-28 23:17:45 +02:00
< / If >
< If condition = { this . showLog . get ( ) } >
2023-02-28 03:01:05 +01:00
< i className = "fa-sharp fa-solid fa-minus" / > Hide Log
2022-10-28 23:17:45 +02:00
< / If >
< / div >
2023-03-19 22:59:21 +01:00
< div className = "flex-spacer" / >
2022-10-28 23:17:45 +02:00
< button onClick = { this . tryReconnect } className = "button" >
2022-08-18 09:39:06 +02:00
< span className = "icon" >
2023-02-28 03:01:05 +01:00
< i className = "fa-sharp fa-solid fa-rotate" / >
2022-08-18 09:39:06 +02:00
< / span >
2022-10-28 23:17:45 +02:00
< span > Try Reconnect < / span >
< / button >
< button onClick = { this . restartServer } className = "button is-danger" style = { { marginLeft : 10 } } >
< span className = "icon" >
2023-02-28 03:01:05 +01:00
< i className = "fa-sharp fa-solid fa-triangle-exclamation" / >
2022-10-28 23:17:45 +02:00
< / span >
< span > Restart Server < / span >
2022-08-18 09:39:06 +02:00
< / button >
2023-03-19 22:59:21 +01:00
< / footer >
2022-08-18 09:39:06 +02:00
< / div >
< / div >
) ;
}
}
2023-03-21 03:22:52 +01:00
@mobxReact . observer
class ClientStopModal extends React . Component < { } , { } > {
@boundMethod
refreshClient() {
GlobalModel . refreshClient ( ) ;
}
render() {
let model = GlobalModel ;
let cdata = model . clientData . get ( ) ;
let mdata : ClientMigrationInfo = ( cdata != null ? cdata.migration : null ) ;
let title = "Client Not Ready" ;
if ( mdata != null ) {
title = "Migrating Data" ;
}
return (
< div className = "prompt-modal client-stop-modal modal is-active" >
< div className = "modal-background" > < / div >
< div className = "modal-content" >
< div className = "message-header" >
< div className = "modal-title" > [ prompt ] { title } < / div >
< / div >
< div className = "inner-content" >
< If condition = { cdata == null } >
< div > Cannot get client data . < / div >
< / If >
< If condition = { cdata != null && cdata . cmdstoretype == "session" } >
< div > Client database is being migrated to the latest version , please wait . < / div >
< If condition = { mdata != null } >
< div className = "progress-container" >
< progress className = "progress is-primary" value = { mdata . migrationpos } max = { mdata . migrationtotal } > { mdata . migrationpos } < / progress >
< / div >
< div className = "progress-text" > { mdata . migrationpos } / { mdata . migrationtotal } < / div >
< / If >
< / If >
< / div >
< footer >
< button onClick = { this . refreshClient } className = "button" >
< span className = "icon" >
< i className = "fa-sharp fa-solid fa-rotate" / >
< / span >
< span > Hard Refresh Client < / span >
< / button >
< / footer >
< / div >
< / div >
) ;
}
}
2023-01-03 07:54:40 +01:00
@mobxReact . observer
class LoadingSpinner extends React . Component < { } , { } > {
render() {
return (
< div className = "loading-spinner" > < div > < / div > < div > < / div > < div > < / div > < div > < / div > < / div >
) ;
}
}
2023-03-03 19:16:31 +01:00
@mobxReact . observer
class AlertModal extends React . Component < { } , { } > {
2023-03-03 21:38:55 +01:00
@boundMethod
2023-03-03 19:16:31 +01:00
closeModal ( ) : void {
2023-03-03 21:38:55 +01:00
GlobalModel . cancelAlert ( ) ;
}
@boundMethod
handleOK ( ) : void {
GlobalModel . confirmAlert ( ) ;
2023-03-03 19:16:31 +01:00
}
render() {
let message = GlobalModel . alertMessage . get ( ) ;
if ( message == null ) {
return null ;
}
2023-04-03 10:39:27 +02:00
let title = message . title ? ? ( message . confirm ? "Confirm" : "Alert" ) ;
2023-03-03 21:38:55 +01:00
let isConfirm = message . confirm ;
2023-03-03 19:16:31 +01:00
return (
2023-03-14 07:36:27 +01:00
< div className = "modal prompt-modal is-active alert-modal" >
2023-03-03 19:16:31 +01:00
< div className = "modal-background" / >
2023-03-14 07:36:27 +01:00
< div className = "modal-content" >
< header >
< p className = "modal-title" > < i className = "fa-sharp fa-solid fa-triangle-exclamation" / > { title } < / p >
< div className = "close-icon" >
< i onClick = { this . closeModal } className = "fa-sharp fa-solid fa-times" / >
< / div >
2023-03-03 19:16:31 +01:00
< / header >
2023-04-04 23:04:44 +02:00
< If condition = { message . markdown } >
< Markdown text = { message . message } extraClassName = "inner-content" / >
< / If >
< If condition = { ! message . markdown } >
< div className = "inner-content content" >
< p > { message . message } < / p >
< / div >
< / If >
2023-03-14 07:36:27 +01:00
< footer >
2023-03-03 21:38:55 +01:00
< If condition = { isConfirm } >
2023-03-15 04:09:59 +01:00
< div onClick = { this . closeModal } className = "button is-prompt-cancel is-outlined is-small" > Cancel < / div >
< div onClick = { this . handleOK } className = "button is-prompt-green is-outlined is-small" > OK < / div >
2023-03-03 21:38:55 +01:00
< / If >
< If condition = { ! isConfirm } >
2023-03-15 04:09:59 +01:00
< div onClick = { this . handleOK } className = "button is-prompt-green is-small" > OK < / div >
2023-03-03 21:38:55 +01:00
< / If >
2023-03-03 19:16:31 +01:00
< / footer >
< / div >
2023-03-14 07:36:27 +01:00
< / div >
) ;
}
}
2023-03-08 05:40:30 +01:00
@mobxReact . observer
class WelcomeModal extends React . Component < { } , { } > {
totalPages : number = 3 ;
pageNum : OV < number > = mobx . observable . box ( 1 , { name : "welcome-pagenum" } ) ;
@boundMethod
closeModal ( ) : void {
mobx . action ( ( ) = > {
GlobalModel . welcomeModalOpen . set ( false ) ;
} ) ( ) ;
}
@boundMethod
goNext ( ) : void {
mobx . action ( ( ) = > {
this . pageNum . set ( this . pageNum . get ( ) + 1 ) ;
} ) ( ) ;
}
@boundMethod
goPrev ( ) : void {
mobx . action ( ( ) = > {
this . pageNum . set ( this . pageNum . get ( ) - 1 ) ;
} ) ( ) ;
}
renderDot ( num : number ) : any {
if ( num == this . pageNum . get ( ) ) {
return < i key = { String ( num ) } className = "fa-sharp fa-solid fa-circle" / > ;
}
return < i key = { String ( num ) } className = "fa-sharp fa-regular fa-circle" / > ;
}
renderDots ( ) : any {
let elems : any = [ ] ;
for ( let i = 1 ; i <= this . totalPages ; i ++ ) {
let elem = this . renderDot ( i ) ;
elems . push ( elem ) ;
}
return elems ;
}
render() {
let pageNum = this . pageNum . get ( ) ;
return (
2023-03-14 07:36:27 +01:00
< div className = { cn ( "modal welcome-modal prompt-modal is-active" ) } >
2023-03-08 05:40:30 +01:00
< div className = "modal-background" / >
< div className = "modal-content" >
< header >
< div className = "modal-title" > welcome to [ prompt ] < / div >
< div className = "close-icon" >
< i onClick = { this . closeModal } className = "fa-sharp fa-solid fa-times" / >
< / div >
< / header >
2023-03-14 07:36:27 +01:00
< div className = { cn ( "inner-content content" , { "is-hidden" : pageNum != 1 } ) } >
2023-03-08 05:40:30 +01:00
< p >
Prompt is a new terminal to help save you time and keep your command - line life organized .
Here ' s a couple quick tips to get your started !
< / p >
< / div >
< footer >
< If condition = { pageNum > 1 } >
< button className = { cn ( "button is-dark prev-button is-small" ) } onClick = { this . goPrev } >
< span className = "icon is-small" >
< i className = "fa-sharp fa-regular fa-angle-left" / >
< / span >
< span > Prev < / span >
< / button >
< / If >
< If condition = { pageNum == 1 } >
< div className = "prev-spacer" / >
< / If >
< div className = "flex-spacer" / >
< div className = "dots" >
{ this . renderDots ( ) }
< / div >
< div className = "flex-spacer" / >
< If condition = { pageNum < this . totalPages } >
< button className = "button is-dark next-button is-small" onClick = { this . goNext } >
< span > Next < / span >
< span className = "icon is-small" >
< i className = "fa-sharp fa-regular fa-angle-right" / >
< / span >
< / button >
< / If >
< If condition = { pageNum == this . totalPages } >
< button className = "button is-dark next-button is-small" onClick = { this . closeModal } >
< span > Done < / span >
< / button >
< / If >
< / footer >
< / div >
< / div >
) ;
}
}
2022-06-16 03:12:22 +02:00
@mobxReact . observer
2022-06-17 00:51:17 +02:00
class Main extends React . Component < { } , { } > {
2023-03-21 03:22:52 +01:00
dcWait : OV < boolean > = mobx . observable . box ( false , { name : "dcWait" } ) ;
2022-06-16 03:12:22 +02:00
constructor ( props : any ) {
super ( props ) ;
}
2023-01-02 23:52:53 +01:00
@boundMethod
handleContextMenu ( e : any ) {
let isInNonTermInput = false ;
let activeElem = document . activeElement ;
if ( activeElem != null && activeElem . nodeName == "TEXTAREA" ) {
if ( ! activeElem . classList . contains ( "xterm-helper-textarea" ) ) {
isInNonTermInput = true ;
}
}
if ( activeElem != null && activeElem . nodeName == "INPUT" && activeElem . getAttribute ( "type" ) == "text" ) {
isInNonTermInput = true ;
}
let opts : ContextMenuOpts = { } ;
if ( isInNonTermInput ) {
opts . showCut = true ;
}
let sel = window . getSelection ( ) ;
if ( ! isBlank ( sel . toString ( ) ) ) {
GlobalModel . contextEditMenu ( e , opts ) ;
}
else {
if ( isInNonTermInput ) {
GlobalModel . contextEditMenu ( e , opts ) ;
}
}
}
2023-03-21 03:22:52 +01:00
@boundMethod
updateDcWait ( val : boolean ) : void {
mobx . action ( ( ) = > {
this . dcWait . set ( val ) ;
} ) ( ) ;
}
2022-06-16 03:12:22 +02:00
render() {
2023-03-14 19:48:14 +01:00
let screenSettingsModal = GlobalModel . screenSettingsModal . get ( ) ;
let sessionSettingsModal = GlobalModel . sessionSettingsModal . get ( ) ;
2023-03-17 20:37:10 +01:00
let lineSettingsModal = GlobalModel . lineSettingsModal . get ( ) ;
2023-03-23 20:08:48 +01:00
let clientSettingsModal = GlobalModel . clientSettingsModal . get ( ) ;
2023-04-03 20:29:54 +02:00
let remotesModal = GlobalModel . remotesModalModel . isOpen ( ) ;
2023-03-21 03:22:52 +01:00
let disconnected = ! GlobalModel . ws . open . get ( ) || ! GlobalModel . localServerRunning . get ( ) ;
let hasClientStop = GlobalModel . getHasClientStop ( ) ;
let dcWait = this . dcWait . get ( ) ;
if ( disconnected || hasClientStop ) {
if ( ! dcWait ) {
setTimeout ( ( ) = > this . updateDcWait ( true ) , 1500 ) ;
}
return (
< div id = "main" onContextMenu = { this . handleContextMenu } >
< div className = "main-content" >
< MainSideBar / >
< div className = "session-view" / >
< / div >
< If condition = { dcWait } >
< If condition = { disconnected } >
< DisconnectedModal / >
< / If >
< If condition = { ! disconnected && hasClientStop } >
< ClientStopModal / >
< / If >
< / If >
< / div >
) ;
}
if ( dcWait ) {
setTimeout ( ( ) = > this . updateDcWait ( false ) , 0 ) ;
}
2022-06-16 03:12:22 +02:00
return (
2023-01-02 23:52:53 +01:00
< div id = "main" onContextMenu = { this . handleContextMenu } >
2022-06-20 22:03:20 +02:00
< div className = "main-content" >
< MainSideBar / >
2022-07-11 23:43:18 +02:00
< SessionView / >
2023-02-03 23:26:46 +01:00
< HistoryView / >
2023-02-21 07:32:11 +01:00
< BookmarksView / >
2023-04-05 08:26:34 +02:00
< WebShareView / >
2022-06-20 22:03:20 +02:00
< / div >
2023-03-03 19:16:31 +01:00
< AlertModal / >
2023-04-05 06:54:20 +02:00
< If condition = { GlobalModel . needsTos ( ) } >
< TosModal / >
< / If >
2023-03-08 05:40:30 +01:00
< If condition = { GlobalModel . welcomeModalOpen . get ( ) } >
< WelcomeModal / >
< / If >
2023-03-14 19:48:14 +01:00
< If condition = { screenSettingsModal != null } >
< ScreenSettingsModal key = { screenSettingsModal . sessionId + ":" + screenSettingsModal . screenId } sessionId = { screenSettingsModal . sessionId } screenId = { screenSettingsModal . screenId } / >
< / If >
< If condition = { sessionSettingsModal != null } >
< SessionSettingsModal key = { sessionSettingsModal } sessionId = { sessionSettingsModal } / >
2023-03-14 07:36:27 +01:00
< / If >
2023-03-17 20:37:10 +01:00
< If condition = { lineSettingsModal != null } >
< LineSettingsModal key = { lineSettingsModal . lineid } line = { lineSettingsModal } / >
< / If >
2023-03-23 20:08:48 +01:00
< If condition = { clientSettingsModal } >
< ClientSettingsModal / >
< / If >
2023-04-03 20:29:54 +02:00
< If condition = { remotesModal } >
< RemotesModal model = { GlobalModel . remotesModalModel } / >
2023-04-03 10:39:27 +02:00
< / If >
2022-06-16 03:12:22 +02:00
< / div >
) ;
}
}
2022-06-08 02:25:35 +02:00
export { Main } ;
2022-07-07 22:27:44 +02:00