mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
add session history
This commit is contained in:
parent
15c3f2fc10
commit
c3626a6547
68
src/main.tsx
68
src/main.tsx
@ -174,39 +174,91 @@ class Line extends React.Component<{line : LineType, session : Session}, {}> {
|
||||
|
||||
@mobxReact.observer
|
||||
class CmdInput extends React.Component<{session : Session, windowid : string}, {}> {
|
||||
curLine : mobx.IObservableValue<string> = mobx.observable("", {name: "command-line"});
|
||||
historyIndex : mobx.IObservableValue<number> = mobx.observable.box(0, {name: "history-index"});
|
||||
modHistory : mobx.IObservableArray<string> = mobx.observable.array([""], {name: "mod-history"});
|
||||
|
||||
@mobx.action @boundMethod
|
||||
onKeyDown(e : any) {
|
||||
mobx.action(() => {
|
||||
let {session} = this.props;
|
||||
let ctrlMod = e.getModifierState("Control") || e.getModifierState("Meta") || e.getModifierState("Shift");
|
||||
if (e.code == "Enter" && !ctrlMod) {
|
||||
e.preventDefault();
|
||||
setTimeout(() => this.doSubmitCmd(), 0);
|
||||
return;
|
||||
}
|
||||
if (e.code == "ArrowUp") {
|
||||
e.preventDefault();
|
||||
let hidx = this.historyIndex.get();
|
||||
hidx += 1;
|
||||
if (hidx > session.getNumHistoryItems()) {
|
||||
hidx = session.getNumHistoryItems();
|
||||
}
|
||||
this.historyIndex.set(hidx);
|
||||
return;
|
||||
}
|
||||
if (e.code == "ArrowDown") {
|
||||
e.preventDefault();
|
||||
let hidx = this.historyIndex.get();
|
||||
hidx -= 1;
|
||||
if (hidx < 0) {
|
||||
hidx = 0;
|
||||
}
|
||||
this.historyIndex.set(hidx);
|
||||
return;
|
||||
}
|
||||
// console.log(e.code, e.keyCode, e.key, event.which, ctrlMod, e);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clearCurLine() {
|
||||
mobx.action(() => {
|
||||
this.historyIndex.set(0);
|
||||
this.modHistory.clear();
|
||||
this.modHistory[0] = "";
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
getCurLine() : string {
|
||||
let {session} = this.props;
|
||||
let hidx = this.historyIndex.get();
|
||||
if (hidx < this.modHistory.length && this.modHistory[hidx] != null) {
|
||||
return this.modHistory[hidx];
|
||||
}
|
||||
let hitem = session.getHistoryItem(-hidx);
|
||||
if (hitem == null) {
|
||||
return "";
|
||||
}
|
||||
return hitem.cmdtext;
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
setCurLine(val : string) {
|
||||
let hidx = this.historyIndex.get();
|
||||
this.modHistory[hidx] = val;
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
onChange(e : any) {
|
||||
mobx.action(() => {
|
||||
this.curLine.set(e.target.value);
|
||||
this.setCurLine(e.target.value);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
doSubmitCmd() {
|
||||
let {session, windowid} = this.props;
|
||||
let commandStr = this.curLine.get();
|
||||
mobx.action(() => {
|
||||
this.curLine.set("");
|
||||
})();
|
||||
let commandStr = this.getCurLine();
|
||||
let hitem = {cmdtext: commandStr};
|
||||
session.addToHistory(hitem);
|
||||
this.clearCurLine();
|
||||
session.submitCommand(windowid, commandStr);
|
||||
}
|
||||
|
||||
render() {
|
||||
let curLine = this.getCurLine();
|
||||
return (
|
||||
<div className="box cmd-input has-background-black">
|
||||
<div className="cmd-input-context">
|
||||
@ -219,7 +271,7 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
|
||||
<div className="button is-static">mike@local</div>
|
||||
</div>
|
||||
<div className="control cmd-input-control is-expanded">
|
||||
<textarea value={this.curLine.get()} onKeyDown={this.onKeyDown} onChange={this.onChange} className="input" type="text"></textarea>
|
||||
<textarea value={curLine} onKeyDown={this.onKeyDown} onChange={this.onChange} className="input" type="text"></textarea>
|
||||
</div>
|
||||
<div className="control cmd-exec">
|
||||
<div onClick={this.doSubmitCmd} className="button">
|
||||
@ -338,7 +390,7 @@ class MainSideBar extends React.Component<{}, {}> {
|
||||
</a></li>
|
||||
<li><a className="activity">
|
||||
<i className="user-status status fa fa-circle"/>
|
||||
<img className="avatar" src="https://i.pravatar.cc/48?img=6"/>
|
||||
<img className="avatar" src="https://i.pravatar.cc/48?img=5"/>
|
||||
Michelle T <div className="tag is-link">2</div>
|
||||
</a></li>
|
||||
</ul>
|
||||
|
@ -38,10 +38,14 @@ function getLineId(line : LineType) : string {
|
||||
}
|
||||
|
||||
type WindowType = {
|
||||
sessionid : string;
|
||||
windowid : string;
|
||||
name : string;
|
||||
lines : LineType[];
|
||||
sessionid : string,
|
||||
windowid : string,
|
||||
name : string,
|
||||
lines : LineType[],
|
||||
};
|
||||
|
||||
type HistoryItem = {
|
||||
cmdtext : string,
|
||||
};
|
||||
|
||||
class Session {
|
||||
@ -51,6 +55,7 @@ class Session {
|
||||
activeWindowId : string;
|
||||
termMap : Record<string, TermWrap> = {};
|
||||
termMapById : Record<string, TermWrap> = {};
|
||||
history : HistoryItem[] = [];
|
||||
|
||||
constructor() {
|
||||
}
|
||||
@ -69,6 +74,31 @@ class Session {
|
||||
});
|
||||
}
|
||||
|
||||
addToHistory(hitem : HistoryItem) {
|
||||
this.history.push(hitem);
|
||||
}
|
||||
|
||||
getNumHistoryItems() : number {
|
||||
return this.history.length;
|
||||
}
|
||||
|
||||
getHistoryItem(index : number) : HistoryItem {
|
||||
if (index == 0) {
|
||||
return null;
|
||||
}
|
||||
if (index > 0) {
|
||||
if (index > this.history.length-1) {
|
||||
return null;
|
||||
}
|
||||
return this.history[index];
|
||||
}
|
||||
let absIndex = Math.abs(index);
|
||||
if (absIndex > this.history.length) {
|
||||
return null;
|
||||
}
|
||||
return this.history[this.history.length-absIndex];
|
||||
}
|
||||
|
||||
getTermWrapByLine(line : LineType) : TermWrap {
|
||||
let termKey = makeTermKey(line.sessionid, line.cmdid, line.windowid, line.lineid);
|
||||
let termWrap = this.termMap[termKey];
|
||||
|
323
src/sh2.less
323
src/sh2.less
@ -3,175 +3,12 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.title.scripthaus-logo-small {
|
||||
padding-left: 10px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 0;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 400;
|
||||
background-color: black;
|
||||
color: rgb(0, 177, 10);
|
||||
position: relative;
|
||||
font-size: 1.5rem;
|
||||
border-bottom: 2px solid #ddd;
|
||||
|
||||
.title-cursor {
|
||||
position: absolute;
|
||||
left: 157px;
|
||||
bottom: 12px;
|
||||
color: rgb(0, 177, 10);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: black;
|
||||
flex-grow: 1;
|
||||
|
||||
.main-sidebar {
|
||||
border-right: 1px solid #aaa;
|
||||
padding: 0 5px 5px 5px;
|
||||
width: 200px;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #ddd;
|
||||
position: relative;
|
||||
|
||||
.menu {
|
||||
padding-top: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.bottom-spacer {
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
p.menu-label {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.menu-list li.new-session {
|
||||
a.new-session {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.fa {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-list li a {
|
||||
color: #bbb;
|
||||
white-space: nowrap;
|
||||
padding: 5px 5px 5px 12px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
|
||||
|
||||
|
||||
.user-status {
|
||||
position: absolute !important;
|
||||
top: 24px !important;
|
||||
left: 32px !important;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
color: #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sub-label {
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.activity {
|
||||
font-weight: bold;
|
||||
color: #ddd;
|
||||
|
||||
.tag {
|
||||
margin-left: 4px;
|
||||
padding: 0 5px 0 5px;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active:hover {
|
||||
background-color: #3273dc;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 8px;
|
||||
margin-right: 5px;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
color: #4e9a06;
|
||||
|
||||
&.offline {
|
||||
color: #cc0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
width: 50px;
|
||||
|
||||
.collapse-container {
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.collapse-container {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: -4px;
|
||||
|
||||
.arrow-container {
|
||||
color: #777;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.session-view {
|
||||
flex-grow: 1;
|
||||
|
||||
@ -181,7 +18,167 @@
|
||||
}
|
||||
}
|
||||
|
||||
.title.scripthaus-logo-small {
|
||||
padding-left: 10px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 0;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 400;
|
||||
background-color: darken(rgb(0, 177, 10), 30%);
|
||||
color: rgb(0, 177, 10);
|
||||
position: relative;
|
||||
font-size: 1.5rem;
|
||||
border-bottom: 2px solid #ddd;
|
||||
|
||||
.title-cursor {
|
||||
position: absolute;
|
||||
left: 157px;
|
||||
bottom: 12px;
|
||||
color: rgb(0, 177, 10);
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.main-sidebar {
|
||||
border-right: 1px solid #aaa;
|
||||
padding: 0 5px 5px 5px;
|
||||
width: 200px;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #ddd;
|
||||
position: relative;
|
||||
background-color: darken(rgb(0, 177, 10), 30%);
|
||||
|
||||
.menu {
|
||||
padding-top: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.bottom-spacer {
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
p.menu-label {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.menu-list li.new-session {
|
||||
a.new-session {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.fa {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-list li a {
|
||||
color: #bbb;
|
||||
white-space: nowrap;
|
||||
padding: 3px 5px 3px 12px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
font-size: 13px;
|
||||
|
||||
.user-status {
|
||||
position: absolute !important;
|
||||
top: 24px !important;
|
||||
left: 32px !important;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
color: #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sub-label {
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.activity {
|
||||
font-weight: bold;
|
||||
color: #ddd;
|
||||
|
||||
.tag {
|
||||
margin-left: 4px;
|
||||
padding: 0 5px 0 5px;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active:hover {
|
||||
background-color: #3273dc;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 8px;
|
||||
margin-right: 5px;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
color: #4e9a06;
|
||||
|
||||
&.offline {
|
||||
color: #cc0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
width: 50px;
|
||||
|
||||
.collapse-container {
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.collapse-container {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: -4px;
|
||||
|
||||
.arrow-container {
|
||||
color: #777;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
|
Loading…
Reference in New Issue
Block a user