mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-22 02:41:23 +01:00
use screenmap instead of screenlist, some tweaks to hints
This commit is contained in:
parent
b9f10fb9b6
commit
6fe54f5fde
@ -6,6 +6,10 @@ import {boundMethod} from "autobind-decorator";
|
||||
import cn from "classnames";
|
||||
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
|
||||
|
||||
function renderCmdText(text : string) : any {
|
||||
return <span>⌘{text}</span>;
|
||||
}
|
||||
|
||||
class CmdStrCode extends React.Component<{cmdstr : string, onUse : () => void, onCopy : () => void, isCopied : boolean, fontSize : "normal" | "large", limitHeight : boolean}, {}> {
|
||||
@boundMethod
|
||||
handleUse(e : any) {
|
||||
@ -65,4 +69,4 @@ class Toggle extends React.Component<{checked : boolean, onChange : (value : boo
|
||||
}
|
||||
}
|
||||
|
||||
export {CmdStrCode, Toggle};
|
||||
export {CmdStrCode, Toggle, renderCmdText};
|
||||
|
@ -12,6 +12,7 @@ import type {LineType, CmdDataType, FeStateType, RemoteType, RemotePtrType, Rend
|
||||
import cn from "classnames";
|
||||
import {TermWrap} from "./term";
|
||||
import type {LineContainerModel} from "./model";
|
||||
import {renderCmdText} from "./elements";
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
|
||||
@ -125,7 +126,7 @@ class LineAvatar extends React.Component<{line : LineType, cmd : Cmd}, {}> {
|
||||
|
||||
|
||||
@mobxReact.observer
|
||||
class LineCmd extends React.Component<{screen : LineContainerModel, line : LineType, width : number, staticRender : boolean, visible : OV<boolean>, onHeightChange : HeightChangeCallbackType, topBorder : boolean, renderMode : RenderModeType, overrideCollapsed : OV<boolean>, noSelect? : boolean}, {}> {
|
||||
class LineCmd extends React.Component<{screen : LineContainerModel, line : LineType, width : number, staticRender : boolean, visible : OV<boolean>, onHeightChange : HeightChangeCallbackType, topBorder : boolean, renderMode : RenderModeType, overrideCollapsed : OV<boolean>, noSelect? : boolean, showHints? : boolean}, {}> {
|
||||
lineRef : React.RefObject<any> = React.createRef();
|
||||
cmdTextRef : React.RefObject<any> = React.createRef();
|
||||
rtnStateDiff : mobx.IObservableValue<string> = mobx.observable.box(null, {name: "linecmd-rtn-state-diff"});
|
||||
@ -514,6 +515,11 @@ class LineCmd extends React.Component<{screen : LineContainerModel, line : LineT
|
||||
</If>
|
||||
</div>
|
||||
</If>
|
||||
<If condition={isSelected && !isFocused}>
|
||||
<div className="cmd-hints">
|
||||
<div className="hint-item color-nohover-white">focus line ({renderCmdText("L")})</div>
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
24
src/main.tsx
24
src/main.tsx
@ -19,6 +19,7 @@ import {BookmarksView} from "./bookmarks";
|
||||
import {HistoryView} from "./history";
|
||||
import {Line, Prompt} from "./linecomps";
|
||||
import {ScreenSettingsModal, SessionSettingsModal} from "./settings";
|
||||
import {renderCmdText} from "./elements";
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
|
||||
@ -41,10 +42,6 @@ type InterObsValue = {
|
||||
timeoutid? : any,
|
||||
};
|
||||
|
||||
function renderCmdText(text : string) : any {
|
||||
return <span>⌘{text}</span>;
|
||||
}
|
||||
|
||||
function isBlank(s : string) : boolean {
|
||||
return (s == null || s == "");
|
||||
}
|
||||
@ -1444,8 +1441,12 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickHistoryHint() : void {
|
||||
clickHistoryHint(e : any) : void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
let inputModel = GlobalModel.inputModel;
|
||||
console.log("hitory hint", inputModel.historyShow.get());
|
||||
if (inputModel.historyShow.get()) {
|
||||
inputModel.resetHistory();
|
||||
}
|
||||
@ -1514,7 +1515,7 @@ class CmdInput extends React.Component<{}, {}> {
|
||||
</div>
|
||||
<div className="cmd-hints">
|
||||
<If condition={!focusVal}><div onClick={this.clickFocusInputHint} className="hint-item color-white">focus input ({renderCmdText("I")})</div></If>
|
||||
<If condition={focusVal}><div onClick={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>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -2173,6 +2174,17 @@ class ScreenTabs extends React.Component<{session : Session}, {}> {
|
||||
showingScreens.push(screen);
|
||||
}
|
||||
}
|
||||
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;
|
||||
});
|
||||
return (
|
||||
<div className="screen-tabs-container">
|
||||
<div className={cn("screen-tabs", {"scrolling": this.scrolling.get()})} ref={this.tabsRef} onScroll={this.handleScroll}>
|
||||
|
29
src/model.ts
29
src/model.ts
@ -2,7 +2,7 @@ import * as mobx from "mobx";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {boundMethod} from "autobind-decorator";
|
||||
import {debounce} from "throttle-debounce";
|
||||
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, boundInt, isModKeyPress} from "./util";
|
||||
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeDataMap, genMergeSimpleData, boundInt, isModKeyPress} from "./util";
|
||||
import {TermWrap} from "./term";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import type {SessionDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenOptsType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType, FeStateType, ContextMenuOpts, RendererContext, RendererModel, PtyDataType, BookmarkType, ClientDataType, HistoryViewDataType, AlertMessageType, HistorySearchParams, FocusTypeStrs, ScreenLinesType, HistoryTypeStrs} from "./types";
|
||||
@ -2228,7 +2228,7 @@ class Model {
|
||||
activeSessionId : OV<string> = mobx.observable.box(null, {name: "activeSessionId"});
|
||||
sessionListLoaded : OV<boolean> = mobx.observable.box(false, {name: "sessionListLoaded"});
|
||||
sessionList : OArr<Session> = mobx.observable.array([], {name: "SessionList", deep: false});
|
||||
screenList : OArr<Screen> = mobx.observable.array([], {name: "ScreenList", deep: false});
|
||||
screenMap : OMap<string, Screen> = mobx.observable.map({}, {name: "ScreenMap", deep: false});
|
||||
ws : WSControl;
|
||||
remotes : OArr<RemoteType> = mobx.observable.array([], {name: "remotes", deep: false});
|
||||
remotesLoaded : OV<boolean> = mobx.observable.box(false, {name: "remotesLoaded"});
|
||||
@ -2580,14 +2580,11 @@ class Model {
|
||||
let update : ModelUpdateType = genUpdate;
|
||||
if ("screens" in update) {
|
||||
if (update.connect) {
|
||||
this.screenList.clear();
|
||||
this.screenMap.clear();
|
||||
}
|
||||
genMergeData(this.screenList, update.screens, (s : Screen) => s.screenId, (sdata : ScreenDataType) => sdata.screenid, (sdata : ScreenDataType) => new Screen(sdata), null);
|
||||
for (let i=0; i<update.screens.length; i++) {
|
||||
let screen = update.screens[i];
|
||||
if (screen.remove) {
|
||||
this.removeScreenLinesByScreenId(screen.screenid);
|
||||
}
|
||||
let mods = genMergeDataMap(this.screenMap, update.screens, (s : Screen) => s.screenId, (sdata : ScreenDataType) => sdata.screenid, (sdata : ScreenDataType) => new Screen(sdata));
|
||||
for (let i=0; i<mods.removed.length; i++) {
|
||||
this.removeScreenLinesByScreenId(mods.removed[i]);
|
||||
}
|
||||
}
|
||||
if ("sessions" in update) {
|
||||
@ -2689,8 +2686,7 @@ class Model {
|
||||
|
||||
getScreenNames() : Record<string, string> {
|
||||
let rtn : Record<string, string> = {};
|
||||
for (let i=0; i<this.screenList.length; i++) {
|
||||
let screen = this.screenList[i];
|
||||
for (let screen of this.screenMap.values()) {
|
||||
rtn[screen.screenId] = screen.name.get();
|
||||
}
|
||||
return rtn;
|
||||
@ -2752,19 +2748,12 @@ class Model {
|
||||
}
|
||||
|
||||
getScreenById(sessionId : string, screenId : string) : Screen {
|
||||
for (let i=0; i<this.screenList.length; i++) {
|
||||
let screen = this.screenList[i];
|
||||
if (screen.screenId == screenId) {
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return this.screenMap.get(screenId);
|
||||
}
|
||||
|
||||
getSessionScreens(sessionId : string) : Screen[] {
|
||||
let rtn : Screen[] = [];
|
||||
for (let i=0; i<this.screenList.length; i++) {
|
||||
let screen = this.screenList[i];
|
||||
for (let screen of this.screenMap.values()) {
|
||||
if (screen.sessionId == sessionId) {
|
||||
rtn.push(screen);
|
||||
}
|
||||
|
42
src/sh2.less
42
src/sh2.less
@ -1671,6 +1671,21 @@ body::-webkit-scrollbar {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-hints {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
display: none;
|
||||
|
||||
.hint-item {
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .cmd-hints {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
body .xterm .xterm-viewport {
|
||||
@ -2782,6 +2797,12 @@ input[type=checkbox] {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.hint-item.color-nohover-green {
|
||||
color: black;
|
||||
background-color: @tab-green;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.hint-item.color-white {
|
||||
color: black;
|
||||
@ -2791,6 +2812,27 @@ input[type=checkbox] {
|
||||
background-color: @term-bright-white;
|
||||
}
|
||||
}
|
||||
|
||||
.hint-item.color-nohover-white {
|
||||
color: black;
|
||||
background-color: @term-white;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.hint-item.color-blue {
|
||||
color: black;
|
||||
background-color: @tab-blue;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.hint-item.color-nohover-blue {
|
||||
color: black;
|
||||
background-color: @tab-blue;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.settings-field {
|
||||
|
41
src/util.ts
41
src/util.ts
@ -142,6 +142,45 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
|
||||
objs.replace(newObjs);
|
||||
}
|
||||
|
||||
function genMergeDataMap<ObjType extends IObjType<DataType>, DataType extends IDataType>(
|
||||
objMap : mobx.ObservableMap<string, ObjType>,
|
||||
dataArr : DataType[],
|
||||
objIdFn : (obj : ObjType) => string,
|
||||
dataIdFn : (data : DataType) => string,
|
||||
ctorFn : (data : DataType) => ObjType,
|
||||
) : {added : string[], removed : string[]}
|
||||
{
|
||||
let rtn : {added : string[], removed : string[]} = {added: [], removed: []};
|
||||
if (dataArr == null || dataArr.length == 0) {
|
||||
return rtn;
|
||||
}
|
||||
for (let i=0; i<dataArr.length; i++) {
|
||||
let dataItem = dataArr[i];
|
||||
let id = dataIdFn(dataItem);
|
||||
let obj = objMap.get(id);
|
||||
if (dataItem.remove) {
|
||||
if (obj != null) {
|
||||
obj.dispose();
|
||||
objMap.delete(id);
|
||||
rtn.removed.push(id);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (obj == null) {
|
||||
if (!dataItem.full) {
|
||||
console.log("cannot create object, dataitem is not full", dataItem);
|
||||
continue
|
||||
}
|
||||
obj = ctorFn(dataItem);
|
||||
objMap.set(id, obj);
|
||||
rtn.added.push(id);
|
||||
continue;
|
||||
}
|
||||
obj.mergeData(dataItem);
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
function parseEnv0(envStr64 : string) : Map<string, string> {
|
||||
let envStr = atob(envStr64);
|
||||
let parts = envStr.split("\x00");
|
||||
@ -182,4 +221,4 @@ function incObs(inum : mobx.IObservableValue<number>) {
|
||||
})();
|
||||
}
|
||||
|
||||
export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, parseEnv0, boundInt, isModKeyPress, incObs};
|
||||
export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeDataMap, genMergeSimpleData, parseEnv0, boundInt, isModKeyPress, incObs};
|
||||
|
Loading…
Reference in New Issue
Block a user