Compare commits

..

75 Commits

Author SHA1 Message Date
Evan Simkowitz f81e0c3583 save work attempting to swap textarea 2024-04-08 17:17:33 -07:00
Evan Simkowitz e5a168f34c making textareainput functional component 2024-04-08 15:48:05 -07:00
Evan Simkowitz cc547e526b save 2024-04-08 14:20:10 -07:00
Evan Simkowitz 1b1e6edaee Merge branch 'main' into evan/inshellisense 2024-04-08 13:47:17 -07:00
Evan Simkowitz 1f5309e097 undo text cursor on prompt area (#559) 2024-04-08 13:47:03 -07:00
Evan Simkowitz f4aeb92d32 Merge branch 'main' into evan/inshellisense 2024-04-08 13:16:01 -07:00
Evan Simkowitz af7cc866d3 Make cmdinput prompt smaller, properly handle select events to take priority over onclick (#558) 2024-04-08 13:15:33 -07:00
Evan Simkowitz b780d5b244 Merge branch 'main' into evan/inshellisense 2024-04-08 11:19:25 -07:00
Evan Simkowitz 37e56acf63 Cleanup unused variables in workspaceview (#557) 2024-04-08 10:17:26 -07:00
Mike Sawka 70088afdb5 daystr custom func (#555)
* working on daystr funcs

* daystr custom function
2024-04-05 22:42:22 -07:00
Evan Simkowitz 455790416d Clean up the input model's auxiliary view logic (#553)
* Clean up the input model's auxiliary view logic

* fix

* save work

* rename appconst

* fix keybindings

* remove debugs

* Add comments

* fix focus order

* givefocus whenever focus var is updated, don't update if nothign changes

* remove debug statements

* one more debug

* revert unnecessary newline

* remove cmdinput placeholder to allow for better window resizing
2024-04-05 17:39:27 -07:00
Cole Lashley eed234a131 added codeedit keybinding fix (#554) 2024-04-05 13:01:51 -07:00
Red J Adaya 5a6575a393 Copy button (#550)
* cop button

* cleanup

* fix wrong type

* updates to try to set the cmdinput position (as well as text).  fix button alignment, change checkmark to green (and extend), and remove the transition from parent component and move to copy (sawka)
2024-04-05 12:06:04 -07:00
Sylvie Crowe 84cea373a8 SSH Bugfixes Early April 2024 (#551)
* fix: add vix for missing known_hosts file

In a recent cleanup, I accidentally deleted this fix from before. This
adds it back.

* chore: clarify that the ssh should use private key
2024-04-05 10:54:12 -07:00
Mike Sawka 181e14f55c try to detect and return mimetype with stream file info (#552) 2024-04-05 10:52:04 -07:00
Evan Simkowitz d81a6ed480 Merge branch 'main' into evan/inshellisense 2024-04-05 10:49:22 -07:00
Evan Simkowitz 1c23701181 Clean up styling and focus behavior for cmdinput (#546)
* Clean up cmdinput

* Remove unused css styles, clicking on textarea will focus back to textarea without closing history

* cleanup logic for activating textarea

* actions buttons should always show, should properly disable inactive views

* clicking actions toggles the view

* remove titlebar spacer, clean up padding

* Make AIChat and HistoryInfo share a common layout

* fix ai chat scroll

* clean up formatting

* fix chat textarea resizing

* align prompt and input

* update infomsg to use auxview

* update comments

* fix widths and key error

* add todo

* adjust padding for input, remove debug

* Don't capture clicks on the prompt area
2024-04-04 19:29:43 -07:00
Cole Lashley 0fe767cdf3 Bugfixes for ai chat code select (#537)
* added uuid to code select to fix some render related bugs

* added input popup type, and fixed aichat computed condition

* fixed stash artifacts
2024-04-04 16:58:26 -07:00
Mike Sawka 097623ab51 have initial run-command return faster to the frontend for quicker updating (#549)
* have initial run-command return faster to the frontend for quicker updating.  cuts time from 70-80ms down to 20ms for an average command

* remove wlogs

* more logging cleanup

* fix focus for when start cmd returns an error
2024-04-04 15:08:45 -07:00
Red J Adaya 9de25e4869 truncate labels (#544) 2024-04-03 09:55:36 -07:00
Evan Simkowitz d8393ae50b Merge branch 'main' into evan/inshellisense 2024-04-02 18:48:59 -07:00
Evan Simkowitz 79deb01ea4 save work 2024-04-02 18:48:38 -07:00
Evan Simkowitz a139633375 Send NumRunningCommands updates via the main bus, regardless of where other updates are being sent (#545) 2024-04-02 18:47:54 -07:00
Evan Simkowitz 12f9a50686 beginning to add autocomplete to textareainput 2024-04-02 18:35:12 -07:00
Evan Simkowitz 239933be3e Got autocomplete working! 2024-04-02 18:14:49 -07:00
Evan Simkowitz 4692cf698b hook up runtime 2024-04-02 17:13:54 -07:00
Evan Simkowitz 907e87c217 expand cwd 2024-04-02 17:05:14 -07:00
Evan Simkowitz f97bb699a1 plumb timeout to waveshell 2024-04-02 16:57:34 -07:00
Evan Simkowitz 077545ed93 bad merrge 2024-04-02 15:50:46 -07:00
Evan Simkowitz 60d0f0e976 Merge branch 'main' into evan/inshellisense 2024-04-02 15:49:32 -07:00
Evan Simkowitz ccc63937b6 Support running ephemeral commands (#543)
* initial

* save work, starting to add backend types

* save work

* save work

* Add EphemeralWriteCloser

* Command pipes thru, triggers infinite loop

* save debugging

* fix bad merge

* save debug statements

* fixing spaghetti

* clean up code

* got cwd override working

* Add separate paths for stdout and stderr writers

* fix stdout/stderr

* env vars are now working

* revert waveshell changes

* Making EphemeralWriteCloser into a more generic BufferedPipe

* formatting

* comment

* delete unused package

* more naming changes

* add package comment

* add UsePty to EphemeralRunOpts

* document UsePty

* ensure only one downstream writer can read from the buffer

* store pointer to syncs

* remove inshellisense stuff for now

* remove debugs

* revert yarn

* remove unnecessary debugs in main-server

* more debugging removed

* revert tsconfig
2024-04-02 15:46:32 -07:00
Evan Simkowitz cd4671e5bb store pointer to syncs 2024-04-02 14:58:39 -07:00
Evan Simkowitz d8a714dd4a ensure only one downstream writer can read from the buffer 2024-04-02 14:28:15 -07:00
Evan Simkowitz e0fa1b2560 document UsePty 2024-04-02 14:19:46 -07:00
Evan Simkowitz 2dffcc9237 add UsePty to EphemeralRunOpts 2024-04-02 14:17:12 -07:00
Evan Simkowitz 70090b8684 add package comment 2024-04-02 14:08:10 -07:00
Evan Simkowitz 3f8952caf4 more naming changes 2024-04-02 14:06:51 -07:00
Evan Simkowitz 15a2486e94 delete unused package 2024-04-02 14:01:57 -07:00
Evan Simkowitz 38aa7016b8 comment 2024-04-02 14:01:03 -07:00
Evan Simkowitz cff353ca94 formatting 2024-04-02 13:59:59 -07:00
Evan Simkowitz 5b440ace65 Making EphemeralWriteCloser into a more generic BufferedPipe 2024-04-02 13:58:56 -07:00
Evan Simkowitz dc7fc2c823 Pull in linting fixes from preact branch (#538)
* Pull in linting fixes from preact branch

* more consts

* one more const

* Revert PureComponent

* revert preact artifavt

* revert another change
2024-04-02 12:30:17 -07:00
Red J Adaya ca5117cda0 Terminal theming (#485)
* init

* use setStyleVar

* backend implementation. scrope level terminal theming.

* only invoke this.applyTermTheme for keys that are updated. command runner for global term theme

* invoke applyTermTheme for global terminal themes as well

* fix nil error

* fix issue were theme can't be found

* fix issue where selected termtheme is not set as default value

* term theme switcher for session

* do not force reload after setting css vars

* fix issues. screenview terminal theme switcher

* remove debugging code

* move getTermThemes to util

* fix global theme reset

* fix workspace theme reset

* fix screenview terminal theme reset issue

* cleanup

* do not apply theme if theme hasn't changed

* do not apply theme if theme hasn't changed in workspace view

* cleanup

* cleanup

* force reload terminal

* fix inconsistency

* fix reset issue

* add a mobx reaction so that theming working when switching sessions

* workig reset

* simplify and cleanup

* refactor

* working global and session terminal theming

* add check

* perf improvement

* more perf improvements

* put reaction componentDidUpdate to make sure ref is already associated to the element

* cleanup

* fix issue where session theme is overriden by global theme on reload

* reduce flickering on reload

* more on reducing flickering on reload

* cleanup

* more cleanup

* fix file not found when no global theme is set

* screen level terminal theming

* update comment

* re-render terminal in history view. cleanup.

* cleanup

* merge main
2024-04-01 23:41:24 -07:00
Evan Simkowitz 87de0dbc44 revert waveshell changes 2024-04-01 22:17:44 -07:00
Evan Simkowitz 74839b8e1b env vars are now working 2024-04-01 22:12:58 -07:00
Evan Simkowitz 8a24953a88 fix stdout/stderr 2024-04-01 20:55:23 -07:00
Evan Simkowitz a95854514a Add separate paths for stdout and stderr writers 2024-04-01 20:51:26 -07:00
Evan Simkowitz 229fcf8cd4 got cwd override working 2024-04-01 18:27:18 -07:00
Evan Simkowitz 83542ddab8 clean up code 2024-04-01 17:42:03 -07:00
Evan Simkowitz b520242f04 fixing spaghetti 2024-04-01 17:12:51 -07:00
Evan Simkowitz bc73ed1b6c save debug statements 2024-04-01 16:04:42 -07:00
Evan Simkowitz c4647945a4 fix bad merge 2024-04-01 14:22:23 -07:00
Evan Simkowitz 3db40b1c63 Merge branch 'main' into evan/inshellisense 2024-04-01 14:22:17 -07:00
Evan Simkowitz f6d7c37915 save debugging 2024-03-29 16:54:29 -07:00
Cole Lashley f41ac1d5e3 Added this.lastHistoryUpDown = false to cmdinput domain callback (#533)
* added more cmdinput-anykey behavior

* fixed lasthistoryupdown

* more bug fixes

* fixed history bugs hopefully fully fixed
2024-03-29 13:28:49 -07:00
Mike Sawka 0024f0f3e8 fix xterm.js versions and addon versions (#534)
* make xterm packages consistent

* add serializeAddon, fix varsUpdated
2024-03-29 10:52:18 -07:00
Mike Sawka 8a3d9628ba add addons-webgl, protected with clientsettings flag (#532) 2024-03-28 23:19:39 -07:00
Mike Sawka 7c2265f3e3 add debug command to see remote-instance state (#531) 2024-03-28 18:53:16 -07:00
Evan Simkowitz a41e866b1f Command pipes thru, triggers infinite loop 2024-03-28 18:44:37 -07:00
Evan Simkowitz a772715ae4 Add EphemeralWriteCloser 2024-03-28 18:02:27 -07:00
Cole Lashley 4f6c2ee39b Other key bind bug fixes (#529) 2024-03-28 17:53:03 -07:00
Mike Sawka a1e4e807cc update statediff algorithm for wavesrv / remote instances (#530)
* remote statemap from waveshell server (diff against initial state)

* move ShellStatePtr from sstore to packet so it can be passed over the wire

* add finalstatebaseptr to cmddone

* much improved diff computation code on wavesrv side

* fix displayname -- now using hash

* add comments, change a couple msh.WriteToPtyBuffer calls to log.Printfs
2024-03-28 16:56:39 -07:00
Evan Simkowitz d32e2aae05 Merge branch 'main' into evan/inshellisense 2024-03-28 16:24:27 -07:00
Cole Lashley 5c85b2b786 Cmdinput keybinding bug fixes (#524)
* added domain callback for every layer

* added domain callback for every layer

* switched dump logs to false

* dropdown fixes

* moved uuid back to constructor
2024-03-28 13:19:20 -07:00
Cole Lashley 4879e90e91 fixed 2 more switches for baseurl (#527) 2024-03-28 13:14:05 -07:00
Evan Simkowitz a61310afc3 Remove datepicker from history until we have a proper date range selection (#526) 2024-03-28 12:21:58 -07:00
Cole Lashley 80c781bf4c added check for no baseurl (#525) 2024-03-28 12:20:58 -07:00
Mike Sawka 33400e65ff restore delete screen button (#522) 2024-03-27 22:42:37 -07:00
Sylvie Crowe 7b58949027 fix: this prevents possible loops while connecting (#521)
A recent change made it possible to get stuck in a loop when connecting
to a remote. This reverts the part of it that caused this while
retaining the other behavior. This makes it possible to add to blank
known_host files again. It also adds a printout to display when a
connection is complete.
2024-03-27 21:19:35 -07:00
Cole Lashley 3be96c949d Debug pane and lookup key (#518)
* added new util functions for logging keyutils and added debug pane

* clean up the formatting
2024-03-27 18:33:29 -07:00
Evan Simkowitz 3f9d52a7e4 save work 2024-03-26 16:04:37 -07:00
Evan Simkowitz a239a8d70e Merge branch 'main' into evan/inshellisense 2024-03-26 13:00:21 -07:00
Evan Simkowitz a1bddd971f save work 2024-03-25 17:43:02 -07:00
Evan Simkowitz 722318f57d save work, starting to add backend types 2024-03-25 10:54:27 -07:00
Evan Simkowitz 3b633328a1 initial 2024-03-22 16:01:08 -07:00
97 changed files with 5130 additions and 2169 deletions
+7 -3
View File
@@ -23,6 +23,7 @@
"@table-nav/react": "^0.0.7",
"@tanstack/match-sorter-utils": "^8.8.4",
"@tanstack/react-table": "^8.10.3",
"@withfig/autocomplete": "^2.652.3",
"autobind-decorator": "^2.4.0",
"base64-js": "^1.5.1",
"classnames": "^2.3.1",
@@ -49,8 +50,10 @@
"tsx-control-statements": "^5.1.1",
"uuid": "^9.0.0",
"winston": "^3.8.2",
"xterm": "^5.0.0",
"xterm-addon-web-links": "^0.9.0"
"xterm": "^5.3.0",
"xterm-addon-web-links": "^0.9.0",
"xterm-addon-serialize": "^0.11.0",
"xterm-addon-webgl": "^0.16.0"
},
"devDependencies": {
"@babel/cli": "^7.17.10",
@@ -75,6 +78,7 @@
"@types/throttle-debounce": "^5.0.1",
"@types/uuid": "^9.0.7",
"@types/webpack-env": "^1.18.3",
"@withfig/autocomplete-types": "^1.30.0",
"babel-loader": "^9.1.3",
"babel-plugin-jsx-control-statements": "^4.1.2",
"copy-webpack-plugin": "^12.0.0",
@@ -103,4 +107,4 @@
"scripts": {
"postinstall": "electron-builder install-app-deps"
}
}
}
+18 -16
View File
@@ -42,16 +42,19 @@
--app-bg-color: black;
--app-accent-color: rgb(88, 193, 66);
--app-accent-bg-color: rgba(88, 193, 66, 0.25);
--app-accent-bg-darker-color: rgba(88, 193, 66, 0.5);
--app-text-color: rgb(211, 215, 207);
--app-text-primary-color: rgb(255, 255, 255);
--app-text-secondary-color: rgb(195, 200, 194);
--app-text-disabled-color: rgb(173, 173, 173);
--app-text-bg-color: rgb(23, 23, 23);
--app-text-bg-disabled-color: rgb(51, 51, 51);
--app-border-color: rgb(51, 51, 51);
--app-maincontent-bg-color: #333;
--app-maincontent-bg-color: rgb(51, 51, 51);
--app-panel-bg-color: rgba(21, 23, 21, 1);
--app-panel-bg-color-dev: rgb(21, 23, 48);
--app-icon-color: rgb(139, 145, 138);
--app-icon-hover-color: #fff;
--app-icon-hover-color: rgb(255, 255, 255);
--app-selected-mask-color: rgba(255, 255, 255, 0.06);
/* global status colors */
@@ -87,7 +90,7 @@
--form-element-border-color: rgba(241, 246, 243, 0.15);
--form-element-bg-color: var(--app-bg-color);
--form-element-text-color: var(--app-text-primary-color);
--form-element-primary-text-color: var(--form-element-text-color);
--form-element-primary-text-color: var(--app-text-primary-color);
--form-element-label-color: var(--app-text-secondary-color);
--form-element-primary-color: var(--app-accent-color);
--form-element-secondary-color: rgba(255, 255, 255, 0.2);
@@ -122,18 +125,18 @@
/* line colors */
--line-sidebar-message-color: rgb(196, 160, 0);
--line-background: rgba(21, 23, 21, 1);
--line-avatar-color: #eceeec;
--line-background: var(--app-panel-bg-color);
--line-avatar-color: rgb(236, 238, 236);
--line-text-color: rgb(211, 215, 207);
--line-svg-fill-color: rgb(150, 152, 150);
--line-svg-hover-fill-color: #eceeec;
--line-svg-hover-fill-color: rgb(236, 238, 236);
--line-separator-color: rgb(126, 126, 126);
--line-error-color: var(--app-error-color);
--line-warning-color: var(--app-warning-color);
--line-base-soft-blue-color: #729fcf;
--line-base-soft-blue-color: rgb(114, 159, 207);
--line-active-border-color: var(--app-accent-color);
--line-selected-bg-color: rgba(255, 255, 255, 0.05);
--line-selected-border-left-color: #777777;
--line-selected-border-left-color: rgb(119, 119, 119);
--line-selected-error-border-color: rgba(204, 0, 0, 0.8);
--line-selected-error-bg-color: rgb(19, 4, 3);
--line-error-bg-color: rgba(200, 0, 0, 0.1);
@@ -152,22 +155,21 @@
/* table colors */
--table-border-color: rgba(241, 246, 243, 0.15);
--table-thead-border-top-color: rgba(250, 250, 250, 0.1);
--table-thead-bright-border-color: #ccc;
--table-thead-bright-border-color: rgb(204, 204, 204);
--table-thead-bg-color: rgba(250, 250, 250, 0.02);
--table-tr-border-bottom-color: rgba(241, 246, 243, 0.15);
--table-tr-hover-bg-color: rgba(255, 255, 255, 0.06);
--table-tr-selected-bg-color: #222;
--table-tr-selected-hover-bg-color: #333;
--table-tr-selected-bg-color: rgb(34, 34, 34);
--table-tr-selected-hover-bg-color: var(--app-maincontent-bg-color);
/* cmdinput colors */
--cmdinput-textarea-bg-color: #171717;
--cmdinput-bg-color: var(--app-text-bg-color);
--cmdinput-text-error-color: var(--term-red);
--cmdinput-history-item-error-color: var(--term-bright-red);
--cmdinput-history-item-selected-error-color: var(--term-bright-red);
--cmdinput-button-bg-color: rgb(88, 193, 66);
--cmdinput-comment-button-bg-color: rgb(57, 113, 255);
--cmdinput-disabled-icon-color: rgb(76, 81, 75, 1);
--cmdinput-history-bg-color: rgb(21, 23, 21, 1);
--cmdinput-button-bg-color: var(--tab-green);
--cmdinput-disabled-bg-color: var(--app-text-bg-disabled-color);
--cmdinput-history-bg-color: var(--app-bg-color);
/* screen view color */
--screen-view-text-caption-color: rgb(139, 145, 138);
+17 -19
View File
@@ -5,20 +5,20 @@
@import url("./term-light.css");
:root {
--app-bg-color: #fefefe;
--app-bg-color: rgb(254, 254, 254);
--app-accent-color: rgb(75, 166, 57);
--app-accent-bg-color: rgba(75, 166, 57, 0.2);
--app-text-color: #000;
--app-text-color: rgb(0, 0, 0);
--app-text-primary-color: rgb(0, 0, 0, 0.9);
--app-text-secondary-color: rgb(0, 0, 0, 0.7);
--app-border-color: rgb(139 145 138);
--app-panel-bg-color: #e0e0e0;
--app-panel-bg-color-dev: #e0e0e0;
--app-icon-color: rgb(80, 80, 80);
--app-icon-hover-color: rgb(100, 100, 100);
--app-panel-bg-color: rgb(224, 224, 224);
--app-panel-bg-color-dev: rgb(224, 224, 224);
--app-icon-color: rgb(110, 110, 110);
--app-icon-hover-color: rgb(80, 80, 80);
--app-selected-mask-color: rgba(0, 0, 0, 0.06);
--input-bg-color: #eeeeee;
--input-bg-color: rgb(238, 238, 238);
/* tab color */
--tab-white: rgb(0, 0, 0, 0.6);
@@ -30,19 +30,19 @@
--table-thead-bg-color: rgba(250, 250, 250, 0.15);
--table-tr-border-bottom-color: rgba(0, 0, 0, 0.15);
--table-tr-hover-bg-color: rgba(0, 0, 0, 0.15);
--table-tr-selected-bg-color: #dddddd;
--table-tr-selected-hover-bg-color: #cccccc;
--table-tr-selected-bg-color: rgb(221, 221, 221);
--table-tr-selected-hover-bg-color: rgb(204, 204, 204);
/* form colors */
--form-element-border-color: rgba(0, 0, 0, 0.3);
--form-element-bg-color: var(--app-bg-color);
--form-element-text-color: var(--app-text-color);
--form-element-primary-text-color: var(--app-bg-color);
--form-element-text-color: var(--app-text-primary-color);
--form-element-primary-text-color: var(--app-text-primary-color);
--form-element-label-color: rgba(0, 0, 0, 0.6);
--form-element-secondary-color: rgba(0, 0, 0, 0.09);
--form-element-icon-color: rgb(0, 0, 0, 0.6);
--form-element-disabled-text-color: #b7b7b7;
--form-element-placeholder-color: #b7b7b7;
--form-element-disabled-text-color: rgb(183, 183, 183);
--form-element-placeholder-color: rgb(183, 183, 183);
--markdown-bg-color: rgb(0, 0, 0, 0.1);
@@ -50,8 +50,6 @@
--modal-header-bottom-border-color: rgba(0, 0, 0, 0.3);
/* cmd input */
--cmdinput-textarea-bg-color: rgba(0, 0, 0, 0.1);
--cmdinput-textarea-border-color: var(--form-element-border-color);
/* scroll colors */
--scrollbar-background-color: var(--app-bg-color);
@@ -64,15 +62,15 @@
--line-actions-inactive-color: rgba(0, 0, 0, 0.3);
--line-actions-active-color: rgba(0, 0, 0, 1);
--logo-button-hover-bg-color: #f0f0f0;
--logo-button-hover-bg-color: rgb(240, 240, 240);
--xterm-viewport-border-color: rgba(0, 0, 0, 0.3);
--datepicker-cell-hover-bg-color: #f0f0f0;
--datepicker-cell-hover-bg-color: rgb(240, 240, 240);
--datepicker-cell-other-text-color: rgba(0, 0, 0, 0.3);
--datepicker-header-fade-color: rgba(0, 0, 0, 0.4);
--datepicker-year-header-bg-color: #f5f5f5;
--datepicker-year-header-border-color: #dcdcdc;
--datepicker-year-header-bg-color: rgb(245, 245, 245);
--datepicker-year-header-border-color: rgb(220, 220, 220);
/* toggle colors */
--toggle-thumb-color: var(--app-bg-color);
+4
View File
@@ -64,3 +64,7 @@ export enum StatusIndicatorLevel {
// matches packet.go
export const ErrorCode_InvalidCwd = "ERRCWD";
export const InputAuxView_History = "history";
export const InputAuxView_Info = "info";
export const InputAuxView_AIChat = "aichat";
+31 -2
View File
@@ -7,12 +7,13 @@ import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, RemotesModel, getApi } from "@/models";
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "@/common/elements";
import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown, Button } from "@/common/elements";
import { commandRtnHandler, isBlank } from "@/util/util";
import { getTermThemes } from "@/util/themeutil";
import * as appconst from "@/app/appconst";
import "./clientsettings.less";
import { MainView } from "../common/elements/mainview";
import { MainView } from "@/common/elements/mainview";
class ClientSettingsKeybindings extends React.Component<{}, {}> {
componentDidMount() {
@@ -73,6 +74,19 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
handleChangeTermTheme(theme: string): void {
// For global terminal theme, the key is global, otherwise it's either
// sessionId or screenId.
const currTheme = GlobalModel.getTermTheme()["global"];
if (currTheme == theme) {
return;
}
const prtn = GlobalCommandRunner.setGlobalTermTheme(theme, false);
commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
handleChangeTelemetry(val: boolean): void {
let prtn: Promise<CommandRtnType> = null;
@@ -193,6 +207,8 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
const curFontSize = GlobalModel.getTermFontSize();
const curFontFamily = GlobalModel.getTermFontFamily();
const curTheme = GlobalModel.getThemeSource();
const termThemes = getTermThemes(GlobalModel.termThemes, "Wave Default");
const currTermTheme = GlobalModel.getTermTheme()["global"] ?? termThemes[0].label;
return (
<MainView className="clientsettings-view" title="Client Settings" onClose={this.handleClose}>
@@ -233,6 +249,19 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
/>
</div>
</div>
<If condition={termThemes.length > 0}>
<div className="settings-field">
<div className="settings-label">Terminal Theme</div>
<div className="settings-input">
<Dropdown
className="terminal-theme-dropdown"
options={termThemes}
defaultValue={currTermTheme}
onChange={this.handleChangeTermTheme}
/>
</div>
</div>
</If>
<div className="settings-field">
<div className="settings-label">Client ID</div>
<div className="settings-input">{cdata.clientid}</div>
+47
View File
@@ -27,6 +27,10 @@
}
}
&.primary.danger {
background: var(--app-error-color);
}
&.primary.outlined {
background: none;
border: 1px solid var(--form-element-primary-color);
@@ -36,6 +40,37 @@
}
}
&.primary.greyoutlined {
background: none;
border: 1px solid var(--app-text-secondary-color);
i {
fill: var(--app-text-secondary-color);
}
}
&.primary.outlined,
&.primary.greyoutlined {
&.hover-danger:hover {
color: var(--form-element-primary-text-color);
border: 1px solid var(--app-error-color);
background: var(--app-error-color);
}
}
&.primary.outlined.danger {
background: none;
border: 1px solid var(--app-error-color);
i {
fill: var(--app-error-color);
}
}
&.greytext {
color: var(--app-text-secondary-color);
}
&.primary.ghost {
background: none;
i {
@@ -43,6 +78,13 @@
}
}
&.primary.ghost.danger {
background: none;
i {
fill: var(--app-error-color);
}
}
&.secondary {
color: var(--form-element-text-color);
background: var(--form-element-secondary-color);
@@ -56,6 +98,11 @@
border: 1px solid var(--form-element-text-color);
}
&.secondary.outlined.danger {
background: none;
border: 1px solid var(--app-error-color);
}
&.secondary.ghost {
background: none;
}
+6 -4
View File
@@ -6,7 +6,7 @@ import "./button.less";
interface ButtonProps {
children: React.ReactNode;
onClick?: () => void;
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
disabled?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
@@ -14,6 +14,7 @@ interface ButtonProps {
autoFocus?: boolean;
className?: string;
termInline?: boolean;
title?: string;
}
class Button extends React.Component<ButtonProps> {
@@ -23,14 +24,14 @@ class Button extends React.Component<ButtonProps> {
};
@boundMethod
handleClick() {
handleClick(e) {
if (this.props.onClick && !this.props.disabled) {
this.props.onClick();
this.props.onClick(e);
}
}
render() {
const { leftIcon, rightIcon, children, disabled, style, autoFocus, termInline, className } = this.props;
const { leftIcon, rightIcon, children, disabled, style, autoFocus, termInline, className, title } = this.props;
return (
<button
@@ -39,6 +40,7 @@ class Button extends React.Component<ButtonProps> {
disabled={disabled}
style={style}
autoFocus={autoFocus}
title={title}
>
{leftIcon && <span className="icon-left">{leftIcon}</span>}
{children}
+7
View File
@@ -0,0 +1,7 @@
.copy-button {
padding: 5px 5px;
.fa-check {
color: var(--app-success-color);
}
}
+51
View File
@@ -0,0 +1,51 @@
import * as React from "react";
import { Button } from "./button";
import { boundMethod } from "autobind-decorator";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import "./copybutton.less";
type CopyButtonProps = {
title: string;
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
};
@mobxReact.observer
class CopyButton extends React.Component<CopyButtonProps, {}> {
isCopied: OV<boolean> = mobx.observable.box(false, { name: "isCopied" });
@boundMethod
handleOnClick(e: React.MouseEvent<HTMLButtonElement>) {
if (this.isCopied.get()) {
return;
}
mobx.action(() => {
this.isCopied.set(true);
})();
setTimeout(() => {
mobx.action(() => {
this.isCopied.set(false);
})();
}, 2000);
if (this.props.onClick) {
this.props.onClick(e);
}
}
render() {
const { title, onClick } = this.props;
const isCopied = this.isCopied.get();
return (
<Button onClick={this.handleOnClick} className="copy-button secondary ghost" title={title}>
{isCopied ? (
<i className="fa-sharp fa-solid fa-check"></i>
) : (
<i className="fa-sharp fa-solid fa-copy"></i>
)}
</Button>
);
}
}
export { CopyButton };
+9 -1
View File
@@ -53,7 +53,7 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
};
this.wrapperRef = React.createRef();
this.menuRef = React.createRef();
this.curUuid == uuidv4();
this.curUuid = uuidv4();
}
componentDidMount() {
@@ -100,6 +100,9 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
@boundMethod
handleClick() {
if (!this.state.isOpen || !this.state.isTouched) {
this.registerKeybindings();
}
this.toggleDropdown();
}
@@ -109,6 +112,7 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
this.registerKeybindings();
}
@boundMethod
registerKeybindings() {
let keybindManager = GlobalModel.keybindManager;
let domain = "dropdown-" + this.curUuid;
@@ -122,6 +126,7 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
});
keybindManager.registerKeybinding("control", domain, "generic:cancel", (waveEvent) => {
this.setState({ isOpen: false });
this.unregisterKeybindings();
return true;
});
keybindManager.registerKeybinding("control", domain, "generic:selectAbove", (waveEvent) => {
@@ -165,10 +170,12 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
}
}
@boundMethod
handleBlur() {
this.unregisterKeybindings();
}
@boundMethod
unregisterKeybindings() {
let domain = "dropdown-" + this.curUuid;
GlobalModel.keybindManager.unregisterDomain(domain);
@@ -189,6 +196,7 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
}
onChange(value);
this.setState({ isOpen: false, isTouched: true });
this.unregisterKeybindings();
}
@boundMethod
+1
View File
@@ -18,3 +18,4 @@ export { Toggle } from "./toggle";
export { Tooltip } from "./tooltip";
export { TabIcon } from "./tabicon";
export { DatePicker } from "./datepicker";
export { CopyButton } from "./copybutton";
+22 -5
View File
@@ -7,8 +7,10 @@ import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import cn from "classnames";
import { GlobalModel } from "@/models";
import { v4 as uuidv4 } from "uuid";
import "./markdown.less";
import { boundMethod } from "autobind-decorator";
function LinkRenderer(props: any): any {
let newUrl = "https://extern?" + encodeURIComponent(props.href);
@@ -28,14 +30,17 @@ function CodeRenderer(props: any): any {
}
@mobxReact.observer
class CodeBlockMarkdown extends React.Component<{ children: React.ReactNode; codeSelectSelectedIndex?: number }, {}> {
class CodeBlockMarkdown extends React.Component<
{ children: React.ReactNode; codeSelectSelectedIndex?: number; uuid: string },
{}
> {
blockIndex: number;
blockRef: React.RefObject<HTMLPreElement>;
constructor(props) {
super(props);
this.blockRef = React.createRef();
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef);
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef, this.props.uuid);
}
render() {
@@ -62,9 +67,21 @@ class Markdown extends React.Component<
{ text: string; style?: any; extraClassName?: string; codeSelect?: boolean },
{}
> {
CodeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number): any {
curUuid: string;
constructor(props) {
super(props);
this.curUuid = uuidv4();
}
@boundMethod
CodeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number, curUuid: string): any {
if (codeSelect) {
return <CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex}>{props.children}</CodeBlockMarkdown>;
return (
<CodeBlockMarkdown codeSelectSelectedIndex={codeSelectIndex} uuid={curUuid}>
{props.children}
</CodeBlockMarkdown>
);
} else {
const clickHandler = (e: React.MouseEvent<HTMLElement>) => {
let blockText = (e.target as HTMLElement).innerText;
@@ -90,7 +107,7 @@ class Markdown extends React.Component<
h5: (props) => HeaderRenderer(props, 5),
h6: (props) => HeaderRenderer(props, 6),
code: (props) => CodeRenderer(props),
pre: (props) => this.CodeBlockRenderer(props, codeSelect, curCodeSelectIndex),
pre: (props) => this.CodeBlockRenderer(props, codeSelect, curCodeSelectIndex, this.curUuid),
};
return (
<div className={cn("markdown content", this.props.extraClassName)} style={this.props.style}>
+1 -1
View File
@@ -312,7 +312,7 @@ class CreateRemoteConnModal extends React.Component<{}, {}> {
endDecoration: (
<InputDecoration>
<Tooltip
message={`(Required) The path to your ssh key file.`}
message={`(Required) The path to your ssh private key file.`}
icon={<i className="fa-sharp fa-regular fa-circle-question" />}
>
<i className="fa-sharp fa-regular fa-circle-question" />
+1 -1
View File
@@ -338,7 +338,7 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
endDecoration: (
<InputDecoration>
<Tooltip
message={`(Required) The path to your ssh key file.`}
message={`(Required) The path to your ssh private key file.`}
icon={<i className="fa-sharp fa-regular fa-circle-question" />}
>
<i className="fa-sharp fa-regular fa-circle-question" />
+39 -2
View File
@@ -11,8 +11,9 @@ import { GlobalModel, GlobalCommandRunner, Screen } from "@/models";
import { SettingsError, Modal, Dropdown, Tooltip } from "@/elements";
import * as util from "@/util/util";
import { Button } from "@/elements";
import { ReactComponent as GlobeIcon } from "@/assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "@/assets/icons/statuscircle.svg";
import { If } from "tsx-control-statements/components";
import { commandRtnHandler } from "@/util/util";
import { getTermThemes } from "@/util/themeutil";
import {
TabColorSelector,
TabIconSelector,
@@ -153,11 +154,34 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
});
}
@boundMethod
handleChangeTermTheme(theme: string): void {
const currTheme = GlobalModel.getTermTheme()[this.screenId];
if (currTheme == theme) {
return;
}
const prtn = GlobalCommandRunner.setScreenTermTheme(this.screenId, theme, false);
commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
selectRemote(cname: string): void {
let prtn = GlobalCommandRunner.screenSetRemote(cname, true, false);
util.commandRtnHandler(prtn, this.errorMessage);
}
render() {
const screen = this.screen;
if (screen == null) {
return null;
}
let color: string = null;
let icon: string = null;
let index: number = 0;
const curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
const termThemes = getTermThemes(GlobalModel.termThemes);
const currTermTheme = GlobalModel.getTermTheme()[this.screenId] ?? termThemes[0].label;
return (
<Modal className="screen-settings-modal">
<Modal.Header onClose={this.closeModal} title={`Tab Settings (${screen.name.get()})`} />
@@ -186,6 +210,19 @@ class ScreenSettingsModal extends React.Component<{}, {}> {
<TabIconSelector screen={screen} errorMessage={this.errorMessage} />
</div>
</div>
<If condition={termThemes.length > 0}>
<div className="settings-field">
<div className="settings-label">Terminal Theme</div>
<div className="settings-input">
<Dropdown
className="terminal-theme-dropdown"
options={termThemes}
defaultValue={currTermTheme}
onChange={this.handleChangeTermTheme}
/>
</div>
</div>
</If>
<div className="settings-field">
<div className="settings-label actions-label">
<div>Actions</div>
+30 -2
View File
@@ -6,8 +6,10 @@ import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { GlobalModel, GlobalCommandRunner, Session } from "@/models";
import { Button } from "@/elements";
import { Toggle, InlineSettingsTextEdit, SettingsError, Modal, Tooltip } from "@/elements";
import { If } from "tsx-control-statements/components";
import { Toggle, InlineSettingsTextEdit, SettingsError, Modal, Tooltip, Button, Dropdown } from "@/elements";
import { commandRtnHandler } from "@/util/util";
import { getTermThemes } from "@/util/themeutil";
import * as util from "@/util/util";
import "./sessionsettings.less";
@@ -76,6 +78,16 @@ class SessionSettingsModal extends React.Component<{}, {}> {
});
}
@boundMethod
handleChangeTermTheme(theme: string): void {
const currTheme = GlobalModel.getTermTheme()[this.sessionId];
if (currTheme == theme) {
return;
}
const prtn = GlobalCommandRunner.setSessionTermTheme(this.sessionId, theme, false);
commandRtnHandler(prtn, this.errorMessage);
}
@boundMethod
dismissError(): void {
mobx.action(() => {
@@ -87,6 +99,9 @@ class SessionSettingsModal extends React.Component<{}, {}> {
if (this.session == null) {
return null;
}
const termThemes = getTermThemes(GlobalModel.termThemes);
const currTermTheme = GlobalModel.getTermTheme()[this.sessionId] ?? termThemes[0].label;
return (
<Modal className="session-settings-modal">
<Modal.Header onClose={this.closeModal} title={`Workspace Settings (${this.session.name.get()})`} />
@@ -104,6 +119,19 @@ class SessionSettingsModal extends React.Component<{}, {}> {
/>
</div>
</div>
<If condition={termThemes.length > 0}>
<div className="settings-field">
<div className="settings-label">Terminal Theme</div>
<div className="settings-input">
<Dropdown
className="terminal-theme-dropdown"
options={termThemes}
defaultValue={currTermTheme}
onChange={this.handleChangeTermTheme}
/>
</div>
</div>
</If>
<div className="settings-field">
<div className="settings-label">
<div>Archived</div>
+4
View File
@@ -357,6 +357,10 @@
cursor: pointer;
}
.wave-button {
padding: 5px 5px;
}
visibility: hidden;
}
+16 -31
View File
@@ -14,7 +14,7 @@ import localizedFormat from "dayjs/plugin/localizedFormat";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { Line } from "@/app/line/linecomps";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
import { TextField, Dropdown, Button, DatePicker } from "@/elements";
import { TextField, Dropdown, Button, CopyButton } from "@/elements";
import { ReactComponent as ChevronLeftIcon } from "@/assets/icons/history/chevron-left.svg";
import { ReactComponent as ChevronRightIcon } from "@/assets/icons/history/chevron-right.svg";
@@ -22,8 +22,6 @@ import { ReactComponent as RightIcon } from "@/assets/icons/history/right.svg";
import { ReactComponent as SearchIcon } from "@/assets/icons/history/search.svg";
import { ReactComponent as TrashIcon } from "@/assets/icons/trash.svg";
import { ReactComponent as CheckedCheckbox } from "@/assets/icons/checked-checkbox.svg";
import { ReactComponent as CheckIcon } from "@/assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "@/assets/icons/history/copy.svg";
import "./history.less";
import { MainView } from "../common/elements/mainview";
@@ -115,7 +113,6 @@ class HistoryCmdStr extends React.Component<
cmdstr: string;
onUse: () => void;
onCopy: () => void;
isCopied: boolean;
fontSize: "normal" | "large";
limitHeight: boolean;
},
@@ -138,24 +135,17 @@ class HistoryCmdStr extends React.Component<
}
render() {
const { isCopied, cmdstr, fontSize, limitHeight } = this.props;
const { cmdstr, fontSize, limitHeight } = this.props;
return (
<div className={cn("cmdstr-code", { "is-large": fontSize == "large" }, { "limit-height": limitHeight })}>
<If condition={isCopied}>
<div key="copied" className="copied-indicator">
<div>copied</div>
</div>
</If>
<div key="code" className="code-div">
<code>{cmdstr}</code>
</div>
<div key="copy" className="actions-block">
<div className="action-item" onClick={this.handleCopy} title="copy">
<CopyIcon className="icon" />
</div>
<div key="use" className="action-item" title="Use Command" onClick={this.handleUse}>
<CheckIcon className="icon" />
</div>
<CopyButton onClick={this.handleCopy} title="Copy" />
<Button className="secondary ghost" title="Use Command" onClick={this.handleUse}>
<i className="fa-sharp fa-solid fa-play"></i>
</Button>
</div>
</div>
);
@@ -190,7 +180,6 @@ class HistoryView extends React.Component<{}, {}> {
tableRszObs: ResizeObserver;
sessionDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "sessionDropdownActive" });
remoteDropdownActive: OV<boolean> = mobx.observable.box(false, { name: "remoteDropdownActive" });
copiedItemId: OV<string> = mobx.observable.box(null, { name: "copiedItemId" });
@boundMethod
handleNext() {
@@ -308,7 +297,6 @@ class HistoryView extends React.Component<{}, {}> {
hvm.setFromDate(null);
return;
}
console.log;
hvm.setFromDate(newDate);
}
@@ -378,14 +366,6 @@ class HistoryView extends React.Component<{}, {}> {
return;
}
navigator.clipboard.writeText(item.cmdstr);
mobx.action(() => {
this.copiedItemId.set(item.historyid);
})();
setTimeout(() => {
mobx.action(() => {
this.copiedItemId.set(null);
})();
}, 600);
}
@boundMethod
@@ -395,7 +375,7 @@ class HistoryView extends React.Component<{}, {}> {
}
mobx.action(() => {
GlobalModel.showSessionView();
GlobalModel.inputModel.setCurLine(item.cmdstr);
GlobalModel.inputModel.updateCmdLine({ str: item.cmdstr, pos: item.cmdstr.length });
setTimeout(() => GlobalModel.inputModel.giveFocus(), 50);
})();
}
@@ -486,10 +466,10 @@ class HistoryView extends React.Component<{}, {}> {
options={this.getRemoteItems(rnames, remoteIds)}
onChange={this.clickLimitRemote}
/>
<div className="fromts">
{/* <div className="fromts">
<div className="fromts-text">From:&nbsp;</div>
<DatePicker selectedDate={new Date()} onSelectDate={this.handleFromTsChange} />
</div>
</div> */}
<div
className="filter-cmds search-checkbox hoverEffect"
title="Filter common commands like 'ls' and 'cd' from the results"
@@ -570,7 +550,6 @@ class HistoryView extends React.Component<{}, {}> {
cmdstr={item.cmdstr}
onUse={() => this.handleUse(item)}
onCopy={() => this.handleCopy(item)}
isCopied={this.copiedItemId.get() == item.historyid}
fontSize="normal"
limitHeight={true}
/>
@@ -670,6 +649,11 @@ class LineContainer extends React.Component<{ historyId: string; width: number }
this.line = hvm.getLineById(this.historyItem.lineid);
}
componentDidMount(): void {
GlobalModel.bumpTermRenderVersion();
GlobalModel.termThemeSrcEl.set(null);
}
@boundMethod
handleHeightChange(lineNum: number, newHeight: number, oldHeight: number): void {
return;
@@ -710,8 +694,9 @@ class LineContainer extends React.Component<{ historyId: string; width: number }
ssStr = sprintf("#%s[%s]", session.name.get(), screen.name.get());
canViewInContext = true;
}
const termRenderVersion = GlobalModel.termRenderVersion.get();
return (
<div className="line-container">
<div className="line-container" key={termRenderVersion}>
<If condition={canViewInContext}>
<div className="line-context">
<div title="View in Context" className="vic-btn" onClick={this.viewInContext}>
-5
View File
@@ -106,11 +106,6 @@
}
}
&.top-border {
border-top: 1px solid #777;
padding: 10px;
}
&:hover .meta .termopts {
display: block;
}
+156 -145
View File
@@ -8,7 +8,7 @@ import { sprintf } from "sprintf-js";
import { boundMethod } from "autobind-decorator";
import dayjs from "dayjs";
import localizedFormat from "dayjs/plugin/localizedFormat";
import { If } from "tsx-control-statements/components";
import { Choose, If, Otherwise, When } from "tsx-control-statements/components";
import { GlobalModel, GlobalCommandRunner, Cmd } from "@/models";
import { termHeightFromRows } from "@/util/textmeasure";
import cn from "classnames";
@@ -25,23 +25,22 @@ import * as lineutil from "./lineutil";
import { ErrorBoundary } from "@/common/error/errorboundary";
import * as appconst from "@/app/appconst";
import * as util from "@/util/util";
import * as textmeasure from "@/util/textmeasure";
import "./line.less";
import { CenteredIcon, RotateIcon } from "../common/icons/icons";
import { RotateIcon } from "../common/icons/icons";
const DebugHeightProblems = false;
const MinLine = 0;
const MaxLine = 1000;
let heightLog = {};
const heightLog = {};
(window as any).heightLog = heightLog;
(window as any).findHeightProblems = function () {
for (let linenum in heightLog) {
let lh = heightLog[linenum];
for (const linenum in heightLog) {
const lh = heightLog[linenum];
if (lh.heightArr == null || lh.heightArr.length < 2) {
continue;
}
let firstHeight = lh.heightArr[0];
const firstHeight = lh.heightArr[0];
for (let i = 1; i < lh.heightArr.length; i++) {
if (lh.heightArr[i] != firstHeight) {
console.log("line", linenum, "heights", lh.heightArr);
@@ -57,7 +56,7 @@ function cmdShouldMarkError(cmd: Cmd): boolean {
if (cmd.getStatus() == "error") {
return true;
}
let exitCode = cmd.getExitCode();
const exitCode = cmd.getExitCode();
// 0, SIGINT, or SIGPIPE
if (exitCode == 0 || exitCode == 130 || exitCode == 141) {
return false;
@@ -142,7 +141,7 @@ class LineActions extends React.Component<{ screen: LineContainerType; line: Lin
handleLineSettings(e: any): void {
e.preventDefault();
e.stopPropagation();
let { line } = this.props;
const { line } = this.props;
if (line != null) {
mobx.action(() => {
GlobalModel.lineSettingsModal.set(line.linenum);
@@ -152,74 +151,89 @@ class LineActions extends React.Component<{ screen: LineContainerType; line: Lin
}
render() {
let { line, screen } = this.props;
const { line, screen } = this.props;
const isMinimized = line.linestate["wave:min"];
const containerType = screen.getContainerType();
return (
<div className="line-actions">
<If condition={containerType == appconst.LineContainer_Main}>
<div key="restart" title="Restart Command" className="line-icon" onClick={this.clickRestart}>
<i className="fa-sharp fa-regular fa-arrows-rotate fa-fw" />
</div>
<div key="delete" title="Delete Line (&#x2318;D)" className="line-icon" onClick={this.clickDelete}>
<i className="fa-sharp fa-regular fa-trash fa-fw" />
</div>
<div
key="bookmark"
title="Bookmark"
className={cn("line-icon", "line-bookmark")}
onClick={this.clickBookmark}
>
<i className="fa-sharp fa-regular fa-bookmark fa-fw" />
</div>
<div
key="minimize"
title={`${isMinimized ? "Show Output" : "Hide Output"}`}
className={cn("line-icon", isMinimized ? "active" : "")}
onClick={this.clickMinimize}
>
<If condition={isMinimized}>
<i className="fa-sharp fa-regular fa-circle-plus fa-fw" />
</If>
<If condition={!isMinimized}>
<i className="fa-sharp fa-regular fa-circle-minus fa-fw" />
</If>
</div>
<div className="line-icon line-sidebar" onClick={this.clickMoveToSidebar} title="Move to Sidebar">
<i className="fa-sharp fa-solid fa-right-to-line fa-fw" />
</div>
<div
key="settings"
title="Line Settings"
className="line-icon line-icon-shrink-left"
onClick={this.handleLineSettings}
>
<i className="fa-sharp fa-regular fa-ellipsis-vertical fa-fw" />
</div>
</If>
<If condition={containerType == appconst.LineContainer_Sidebar}>
<div key="restart" title="Restart Command" className="line-icon" onClick={this.clickRestart}>
<i className="fa-sharp fa-regular fa-arrows-rotate fa-fw" />
</div>
<div key="delete" title="Delete Line (&#x2318;D)" className="line-icon" onClick={this.clickDelete}>
<i className="fa-sharp fa-regular fa-trash fa-fw" />
</div>
<div
key="bookmark"
title="Bookmark"
className={cn("line-icon", "line-bookmark")}
onClick={this.clickBookmark}
>
<i className="fa-sharp fa-regular fa-bookmark fa-fw" />
</div>
<div
className="line-icon line-sidebar"
onClick={this.clickRemoveFromSidebar}
title="Move to Sidebar"
>
<i className="fa-sharp fa-solid fa-left-to-line fa-fw" />
</div>
</If>
<Choose>
<When condition={containerType == appconst.LineContainer_Main}>
<div key="restart" title="Restart Command" className="line-icon" onClick={this.clickRestart}>
<i className="fa-sharp fa-regular fa-arrows-rotate fa-fw" />
</div>
<div
key="delete"
title="Delete Line (&#x2318;D)"
className="line-icon"
onClick={this.clickDelete}
>
<i className="fa-sharp fa-regular fa-trash fa-fw" />
</div>
<div
key="bookmark"
title="Bookmark"
className={cn("line-icon", "line-bookmark")}
onClick={this.clickBookmark}
>
<i className="fa-sharp fa-regular fa-bookmark fa-fw" />
</div>
<div
key="minimize"
title={`${isMinimized ? "Show Output" : "Hide Output"}`}
className={cn("line-icon", isMinimized ? "active" : "")}
onClick={this.clickMinimize}
>
<Choose>
<When condition={isMinimized}>
<i className="fa-sharp fa-regular fa-circle-plus fa-fw" />
</When>
<Otherwise>
<i className="fa-sharp fa-regular fa-circle-minus fa-fw" />
</Otherwise>
</Choose>
</div>
<div
className="line-icon line-sidebar"
onClick={this.clickMoveToSidebar}
title="Move to Sidebar"
>
<i className="fa-sharp fa-solid fa-right-to-line fa-fw" />
</div>
<div
key="settings"
title="Line Settings"
className="line-icon line-icon-shrink-left"
onClick={this.handleLineSettings}
>
<i className="fa-sharp fa-regular fa-ellipsis-vertical fa-fw" />
</div>
</When>
<When condition={containerType == appconst.LineContainer_Sidebar}>
<div
key="delete"
title="Delete Line (&#x2318;D)"
className="line-icon"
onClick={this.clickDelete}
>
<i className="fa-sharp fa-regular fa-trash fa-fw" />
</div>
<div
key="bookmark"
title="Bookmark"
className={cn("line-icon", "line-bookmark")}
onClick={this.clickBookmark}
>
<i className="fa-sharp fa-regular fa-bookmark fa-fw" />
</div>
<div
className="line-icon line-sidebar"
onClick={this.clickRemoveFromSidebar}
title="Move to Sidebar"
>
<i className="fa-sharp fa-solid fa-left-to-line fa-fw" />
</div>
</When>
</Choose>
</div>
);
}
@@ -254,9 +268,9 @@ class LineHeader extends React.Component<{ screen: LineContainerType; line: Line
}
renderMeta1(cmd: Cmd) {
let { line } = this.props;
const { line } = this.props;
let formattedTime: string = "";
let restartTs = cmd.getRestartTs();
const restartTs = cmd.getRestartTs();
let timeTitle: string = null;
if (restartTs != null && restartTs > 0) {
formattedTime = "restarted @ " + lineutil.getLineDateTimeStr(restartTs);
@@ -264,8 +278,8 @@ class LineHeader extends React.Component<{ screen: LineContainerType; line: Line
} else {
formattedTime = lineutil.getLineDateTimeStr(line.ts);
}
let renderer = line.renderer;
let durationMs = cmd.getDurationMs();
const renderer = line.renderer;
const durationMs = cmd.getDurationMs();
return (
<div key="meta1" className="meta meta-line1">
<SmallLineAvatar line={line} cmd={cmd} />
@@ -287,7 +301,7 @@ class LineHeader extends React.Component<{ screen: LineContainerType; line: Line
}
render() {
let { line, cmd } = this.props;
const { line, cmd } = this.props;
const hidePrompt = getIsHidePrompt(line);
return (
<div key="header" className={cn("line-header", { "hide-prompt": hidePrompt })}>
@@ -303,7 +317,7 @@ class SmallLineAvatar extends React.Component<{ line: LineType; cmd: Cmd; onRigh
render() {
const { line, cmd } = this.props;
const lineNumStr = (line.linenumtemp ? "~" : "#") + String(line.linenum);
let status = cmd != null ? cmd.getStatus() : "done";
const status = cmd != null ? cmd.getStatus() : "done";
const exitcode = cmd != null ? cmd.getExitCode() : 0;
const isComment = line.linetype == "text";
let icon = null;
@@ -359,7 +373,7 @@ class RtnState extends React.Component<{ cmd: Cmd; line: LineType }> {
}
checkStateDiffLoad(): void {
let cmd = this.props.cmd;
const cmd = this.props.cmd;
if (cmd == null || !cmd.getRtnState() || this.rtnStateDiffFetched) {
return;
}
@@ -406,7 +420,7 @@ class RtnState extends React.Component<{ cmd: Cmd; line: LineType }> {
}
render() {
let { cmd } = this.props;
const { cmd } = this.props;
const rsdiff = this.rtnStateDiff.get();
const termFontSize = GlobalModel.getTermFontSize();
let rtnStateDiffSize = termFontSize - 2;
@@ -488,7 +502,7 @@ class LineCmd extends React.Component<
if (elem != null) {
curHeight = elem.offsetHeight;
}
let linenum = line.linenum;
const linenum = line.linenum;
if (DebugHeightProblems && linenum >= MinLine && linenum <= MaxLine) {
heightLog[linenum] = heightLog[linenum] || {};
heightLog[linenum].heightArr = heightLog[linenum].heightArr || [];
@@ -685,7 +699,7 @@ class LineCmd extends React.Component<
const isFocused = mobx
.computed(
() => {
let screenFocusType = screen.getFocusType();
const screenFocusType = screen.getFocusType();
return isPhysicalFocused && screenFocusType == "cmd";
},
{ name: "computed-isFocused" }
@@ -694,7 +708,7 @@ class LineCmd extends React.Component<
const shouldCmdFocus = mobx
.computed(
() => {
let screenFocusType = screen.getFocusType();
const screenFocusType = screen.getFocusType();
return isSelected && screenFocusType == "cmd";
},
{ name: "computed-shouldCmdFocus" }
@@ -725,16 +739,9 @@ class LineCmd extends React.Component<
rendererPlugin = PluginModel.getRendererPluginByName(line.renderer);
}
const rendererType = lineutil.getRendererType(line);
const hidePrompt = rendererPlugin?.hidePrompt;
const termFontSize = GlobalModel.getTermFontSize();
const containerType = screen.getContainerType();
const isMinimized = line.linestate["wave:min"] && containerType == appconst.LineContainer_Main;
const lhv: LineChromeHeightVars = {
numCmdLines: lineutil.countCmdLines(cmd.getCmdStr()),
zeroHeight: isMinimized,
hasLine2: !hidePrompt,
};
const chromeHeight = textmeasure.calcLineChromeHeight(GlobalModel.lineHeightEnv, lhv);
return (
<div
className={mainDivCn}
@@ -749,55 +756,64 @@ class LineCmd extends React.Component<
</If>
<LineActions screen={screen} line={line} cmd={cmd} />
<LineHeader screen={screen} line={line} cmd={cmd} />
<If condition={!isMinimized && isInSidebar}>
<div className="sidebar-message" style={{ fontSize: termFontSize }}>
&nbsp;&nbsp;showing in sidebar =&gt;
</div>
</If>
<If condition={!isMinimized && !isInSidebar}>
<ErrorBoundary plugin={rendererPlugin?.name} lineContext={lineutil.getRendererContext(line)}>
<If condition={rendererPlugin == null && !isNoneRenderer}>
<TerminalRenderer
screen={screen}
line={line}
width={width}
staticRender={staticRender}
visible={visible}
onHeightChange={this.handleHeightChange}
collapsed={false}
/>
</If>
<If condition={rendererPlugin != null && rendererPlugin.rendererType == "simple"}>
<SimpleBlobRenderer
rendererContainer={screen}
lineId={line.lineid}
plugin={rendererPlugin}
onHeightChange={this.handleHeightChange}
initParams={this.makeRendererModelInitializeParams()}
scrollToBringIntoViewport={this.scrollToBringIntoViewport}
isSelected={isSelected}
shouldFocus={shouldCmdFocus}
/>
</If>
<If condition={rendererPlugin != null && rendererPlugin.rendererType == "full"}>
<IncrementalRenderer
rendererContainer={screen}
lineId={line.lineid}
plugin={rendererPlugin}
onHeightChange={this.handleHeightChange}
initParams={this.makeRendererModelInitializeParams()}
isSelected={isSelected}
/>
</If>
</ErrorBoundary>
<If condition={isRtnState}>
<RtnState cmd={cmd} line={line} />
</If>
<If condition={isSelected && !isFocused && rendererType == "terminal"}>
<div className="cmd-hints">
<div className="hint-item color-nohover-white">focus line ({renderCmdText("L")})</div>
</div>
</If>
<If condition={!isMinimized}>
<Choose>
<When condition={isInSidebar}>
<div className="sidebar-message" style={{ fontSize: termFontSize }}>
&nbsp;&nbsp;showing in sidebar =&gt;
</div>
</When>
<Otherwise>
<ErrorBoundary
plugin={rendererPlugin?.name}
lineContext={lineutil.getRendererContext(line)}
>
<If condition={rendererPlugin == null && !isNoneRenderer}>
<TerminalRenderer
screen={screen}
line={line}
width={width}
staticRender={staticRender}
visible={visible}
onHeightChange={this.handleHeightChange}
collapsed={false}
/>
</If>
<If condition={rendererPlugin != null && rendererPlugin.rendererType == "simple"}>
<SimpleBlobRenderer
rendererContainer={screen}
lineId={line.lineid}
plugin={rendererPlugin}
onHeightChange={this.handleHeightChange}
initParams={this.makeRendererModelInitializeParams()}
scrollToBringIntoViewport={this.scrollToBringIntoViewport}
isSelected={isSelected}
shouldFocus={shouldCmdFocus}
/>
</If>
<If condition={rendererPlugin != null && rendererPlugin.rendererType == "full"}>
<IncrementalRenderer
rendererContainer={screen}
lineId={line.lineid}
plugin={rendererPlugin}
onHeightChange={this.handleHeightChange}
initParams={this.makeRendererModelInitializeParams()}
isSelected={isSelected}
/>
</If>
</ErrorBoundary>
<If condition={isRtnState}>
<RtnState cmd={cmd} line={line} />
</If>
<If condition={isSelected && !isFocused && rendererType == "terminal"}>
<div className="cmd-hints">
<div className="hint-item color-nohover-white">
focus line ({renderCmdText("L")})
</div>
</div>
</If>
</Otherwise>
</Choose>
</If>
</div>
);
@@ -877,11 +893,6 @@ class LineText extends React.Component<
name: "computed-isSelected",
})
.get();
const isFocused = mobx
.computed(() => screen.getFocusType() == "cmd", {
name: "computed-isFocused",
})
.get();
const mainClass = cn("line", "line-text", "focus-parent", { selected: isSelected });
return (
<div

Some files were not shown because too many files have changed in this diff Show More