mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
working on history inbox view
This commit is contained in:
+3
-3
@@ -172,9 +172,9 @@ class BookmarksView extends React.Component<{}, {}> {
|
||||
let idx : number = 0;
|
||||
let bookmark : BookmarkType = null;
|
||||
return (
|
||||
<div className={cn("bookmarks-view", {"is-hidden": isHidden})}>
|
||||
<div className={cn("bookmarks-view", "alt-view", {"is-hidden": isHidden})}>
|
||||
<div className="close-button" onClick={this.clickHandler}><i className="fa-sharp fa-solid fa-xmark"></i></div>
|
||||
<div className="bookmarks-title">
|
||||
<div className="alt-title">
|
||||
<i className="fa-sharp fa-solid fa-bookmark" style={{marginRight: 10}}/>
|
||||
BOOKMARKS
|
||||
</div>
|
||||
@@ -190,7 +190,7 @@ class BookmarksView extends React.Component<{}, {}> {
|
||||
</If>
|
||||
</div>
|
||||
<If condition={bookmarks.length > 0}>
|
||||
<div className="bookmarks-help">
|
||||
<div className="alt-help">
|
||||
<div className="help-entry">
|
||||
[Enter] to Use Bookmark<br/>
|
||||
[Backspace/Delete]x2 or <i className="fa-sharp fa-solid fa-trash"/> to Delete<br/>
|
||||
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
import * as React from "react";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import * as mobx from "mobx";
|
||||
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {boundMethod} from "autobind-decorator";
|
||||
import cn from "classnames";
|
||||
import {GlobalModel, GlobalCommandRunner} from "./model";
|
||||
import {HistoryItem, RemotePtrType} from "./types";
|
||||
import dayjs from "dayjs";
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
import {Line} from "./linecomps";
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
|
||||
const PageSize = 50;
|
||||
|
||||
function isBlank(s : string) {
|
||||
return (s == null || s == "");
|
||||
}
|
||||
|
||||
function getHistoryViewTs(nowDate : Date, ts : number) : string {
|
||||
let itemDate = new Date(ts);
|
||||
if (nowDate.getFullYear() != itemDate.getFullYear()) {
|
||||
return dayjs(itemDate).format("M/D/YY");
|
||||
}
|
||||
else if (nowDate.getMonth() != itemDate.getMonth() || nowDate.getDate() != itemDate.getDate()) {
|
||||
return dayjs(itemDate).format("MMM D");
|
||||
}
|
||||
else {
|
||||
return dayjs(itemDate).format("h:mm A");
|
||||
}
|
||||
}
|
||||
|
||||
function formatRemoteName(rnames : Record<string, string>, rptr : RemotePtrType) : string {
|
||||
if (rptr == null || isBlank(rptr.remoteid)) {
|
||||
return "";
|
||||
}
|
||||
let rname = rnames[rptr.remoteid];
|
||||
if (rname == null) {
|
||||
rname = rptr.remoteid.substr(0, 8);
|
||||
}
|
||||
if (!isBlank(rptr.name)) {
|
||||
rname = rname + ":" + rptr.name;
|
||||
}
|
||||
return "[" + rname + "]";
|
||||
}
|
||||
|
||||
function formatSSName(snames : Record<string, string>, scrnames : Record<string, string>, item : HistoryItem) : string {
|
||||
if (isBlank(item.sessionid)) {
|
||||
return "";
|
||||
}
|
||||
let sessionName = "#" + (snames[item.sessionid] ?? item.sessionid.substr(0, 8));
|
||||
if (isBlank(item.screenid)) {
|
||||
return sessionName;
|
||||
}
|
||||
// let screenName = "/" + (scrnames[item.screenid] ?? item.screenid.substr(0, 8));
|
||||
// return sessionName + screenName;
|
||||
return sessionName;
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class HistoryView extends React.Component<{}, {}> {
|
||||
@boundMethod
|
||||
clickCloseHandler() : void {
|
||||
GlobalModel.historyViewModel.closeView();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleNext() {
|
||||
GlobalModel.historyViewModel.goNext();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handlePrev() {
|
||||
GlobalModel.historyViewModel.goPrev();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
changeSearchText(e : any) {
|
||||
mobx.action(() => {
|
||||
GlobalModel.historyViewModel.searchText.set(e.target.value);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
searchKeyDown(e : any) {
|
||||
if (e.code == "Enter") {
|
||||
e.preventDefault();
|
||||
GlobalModel.historyViewModel.submitSearch();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleSelect(historyId : string) {
|
||||
let hvm = GlobalModel.historyViewModel;
|
||||
mobx.action(() => {
|
||||
if (hvm.selectedItems.get(historyId)) {
|
||||
hvm.selectedItems.delete(historyId);
|
||||
}
|
||||
else {
|
||||
hvm.selectedItems.set(historyId, true);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleControlCheckbox() {
|
||||
let hvm = GlobalModel.historyViewModel;
|
||||
mobx.action(() => {
|
||||
let numSelected = hvm.selectedItems.size;
|
||||
if (numSelected > 0) {
|
||||
hvm.selectedItems.clear();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
for (let i=0; i<hvm.items.length && i<PageSize; i++) {
|
||||
hvm.selectedItems.set(hvm.items[i].historyid, true);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleClickDelete() {
|
||||
GlobalModel.historyViewModel.doSelectedDelete();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
activateItem(historyId : string) {
|
||||
if (GlobalModel.historyViewModel.activeItem.get() == historyId) {
|
||||
GlobalModel.historyViewModel.setActiveItem(null);
|
||||
}
|
||||
else {
|
||||
GlobalModel.historyViewModel.setActiveItem(historyId);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let isHidden = (GlobalModel.activeMainView.get() != "history");
|
||||
if (isHidden) {
|
||||
return null;
|
||||
}
|
||||
let hvm = GlobalModel.historyViewModel;
|
||||
let idx : number = 0;
|
||||
let item : HistoryItem = null;
|
||||
let items = hvm.items.slice();
|
||||
let nowDate = new Date();
|
||||
let snames = GlobalModel.getSessionNames();
|
||||
let rnames = GlobalModel.getRemoteNames();
|
||||
let scrnames = GlobalModel.getScreenNames();
|
||||
let hasMore = false;
|
||||
if (items.length > PageSize) {
|
||||
items = items.slice(0, PageSize);
|
||||
hasMore = true;
|
||||
}
|
||||
let offset = hvm.offset.get();
|
||||
let numSelected = hvm.selectedItems.size;
|
||||
let controlCheckboxIcon = "fa-sharp fa-regular fa-square";
|
||||
if (numSelected > 0) {
|
||||
controlCheckboxIcon = "fa-sharp fa-regular fa-square-minus";
|
||||
}
|
||||
if (numSelected > 0 && numSelected == items.length) {
|
||||
controlCheckboxIcon = "fa-sharp fa-regular fa-square-check";
|
||||
}
|
||||
let activeItem = hvm.activeItem.get();
|
||||
return (
|
||||
<div className={cn("history-view", "alt-view", {"is-hidden": isHidden})}>
|
||||
<div className="close-button" onClick={this.clickCloseHandler}><i className="fa-sharp fa-solid fa-xmark"></i></div>
|
||||
<div className="header">
|
||||
<div className="history-title">
|
||||
HISTORY
|
||||
</div>
|
||||
<div className="history-search">
|
||||
<div className="field">
|
||||
<p className="control has-icons-left">
|
||||
<input className="input" type="text" placeholder="Search" value={hvm.searchText.get()} onChange={this.changeSearchText} onKeyDown={this.searchKeyDown}/>
|
||||
<span className="icon is-small is-left">
|
||||
<i className="fa-sharp fa-solid fa-search"/>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="control-bar">
|
||||
<div className="control-checkbox" onClick={this.handleControlCheckbox}>
|
||||
<i className={controlCheckboxIcon} title="Toggle Selection"/>
|
||||
</div>
|
||||
<div className={cn("control-button delete-button", {"is-disabled": (numSelected == 0)}, {"is-active": hvm.deleteActive.get()})} onClick={this.handleClickDelete}>
|
||||
<i className="fa-sharp fa-solid fa-trash" title="Purge Selected Items"/>
|
||||
</div>
|
||||
<div className="spacer"/>
|
||||
<div className="showing-text">Showing {offset+1}-{offset+items.length}</div>
|
||||
<div className={cn("showing-btn", {"is-disabled": (offset == 0)})} onClick={(offset != 0 ? this.handlePrev : null)}><i className="fa-sharp fa-solid fa-chevron-left"/></div>
|
||||
<div className="btn-spacer"/>
|
||||
<div className={cn("showing-btn", {"is-disabled": !hasMore})} onClick={hasMore ? this.handleNext : null}><i className="fa-sharp fa-solid fa-chevron-right"/></div>
|
||||
</div>
|
||||
<table className="history-table" cellSpacing="0" cellPadding="0" border={0}>
|
||||
<tbody>
|
||||
<For index="idx" each="item" of={items}>
|
||||
<tr key={item.historyid} className={cn("history-item", {"is-selected": hvm.selectedItems.get(item.historyid)})}>
|
||||
<td className="selectbox" onClick={() => this.handleSelect(item.historyid)}>
|
||||
<If condition={hvm.selectedItems.get(item.historyid)}>
|
||||
<i className="fa-sharp fa-regular fa-square-check"></i>
|
||||
</If>
|
||||
<If condition={!hvm.selectedItems.get(item.historyid)}>
|
||||
<i className="fa-sharp fa-regular fa-square"></i>
|
||||
</If>
|
||||
</td>
|
||||
<td className="bookmark" style={{display: "none"}}>
|
||||
<i className="fa-sharp fa-regular fa-bookmark"/>
|
||||
</td>
|
||||
<td className="ts">
|
||||
{getHistoryViewTs(nowDate, item.ts)}
|
||||
</td>
|
||||
<td className="session">
|
||||
{formatSSName(snames, scrnames, item)}
|
||||
</td>
|
||||
<td className="remote">
|
||||
{formatRemoteName(rnames, item.remote)}
|
||||
</td>
|
||||
<td className="cmdstr" onClick={() => this.activateItem(item.historyid)}>
|
||||
{item.cmdstr}
|
||||
</td>
|
||||
</tr>
|
||||
<If condition={activeItem == item.historyid}>
|
||||
<tr className="active-history-item">
|
||||
<td colSpan={10}>
|
||||
<line sw={hvm.specialLineContainer} line={null} width={600} staticRender={true} visible={null} onHeightChange={null} overrideCollapsed={null} topBorder={false} renderMode="normal"/>
|
||||
</td>
|
||||
</tr>
|
||||
</If>
|
||||
</For>
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="alt-help">
|
||||
<div className="help-entry">
|
||||
[Esc] to Close<br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export {HistoryView};
|
||||
File diff suppressed because it is too large
Load Diff
+71
-886
File diff suppressed because it is too large
Load Diff
+266
-3
@@ -5,7 +5,7 @@ import {debounce} from "throttle-debounce";
|
||||
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, boundInt, isModKeyPress} from "./util";
|
||||
import {TermWrap} from "./term";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType, FeStateType, ContextMenuOpts, RendererContext, RendererModel, PtyDataType, BookmarkType, ClientDataType} from "./types";
|
||||
import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType, FeStateType, ContextMenuOpts, RendererContext, RendererModel, PtyDataType, BookmarkType, ClientDataType, HistoryViewDataType} from "./types";
|
||||
import {WSControl} from "./ws";
|
||||
import {ImageRendererModel} from "./imagerenderer";
|
||||
import {measureText, getMonoFontSize} from "./textmeasure";
|
||||
@@ -28,6 +28,17 @@ const VERSION = __PROMPT_VERSION__;
|
||||
// @ts-ignore
|
||||
const BUILD = __PROMPT_BUILD__;
|
||||
|
||||
type LineContainerModel = {
|
||||
loadTerminalRenderer : (elem : Element, line : LineType, cmd : Cmd, width : number) => void,
|
||||
loadImageRenderer : (imageDivElem : any, line : LineType, cmd : Cmd) => ImageRendererModel,
|
||||
unloadRenderer : (cmdId : string) => void,
|
||||
getUsedRows : (line : LineType, cmd : Cmd, width : number) => number,
|
||||
getIsFocused : (lineNum : number) => boolean,
|
||||
getRenderer : (cmdId : string) => RendererModel,
|
||||
getFocusType : () => "input" | "cmd" | "cmd-fg",
|
||||
getSelectedLine : () => number,
|
||||
}
|
||||
|
||||
|
||||
type SWLinePtr = {
|
||||
line : LineType,
|
||||
@@ -408,6 +419,10 @@ class ScreenWindow {
|
||||
})();
|
||||
}
|
||||
|
||||
getFocusType() : "input" | "cmd" | "cmd-fg" {
|
||||
return this.focusType.get();
|
||||
}
|
||||
|
||||
setAnchor(anchorLine : number, anchorOffset : number) : void {
|
||||
let setVal = ((anchorLine == null || anchorLine == 0) ? "0" : sprintf("%d:%d", anchorLine, anchorOffset));
|
||||
GlobalCommandRunner.swSetAnchor(this.sessionId, this.screenId, this.windowId, setVal);
|
||||
@@ -648,6 +663,10 @@ class ScreenWindow {
|
||||
return (this.termLineNumFocus.get() == lineNum);
|
||||
}
|
||||
|
||||
getSelectedLine() : number {
|
||||
return this.selectedLine.get();
|
||||
}
|
||||
|
||||
getWindow() : Window {
|
||||
return GlobalModel.getWindowById(this.sessionId, this.windowId);
|
||||
}
|
||||
@@ -1612,6 +1631,186 @@ type LineFocusType = {
|
||||
cmdid? : string,
|
||||
};
|
||||
|
||||
class SpecialHistoryViewLineContainer {
|
||||
historyItem : HistoryItem;
|
||||
renderer : RendererModel;
|
||||
|
||||
constructor(hitem : HistoryItem) {
|
||||
this.historyItem = hitem;
|
||||
}
|
||||
|
||||
loadTerminalRenderer(elem : Element, line : LineType, cmd : Cmd, width : number) : void {
|
||||
this.unloadRenderer(null);
|
||||
}
|
||||
|
||||
loadImageRenderer(imageDivElem : any, line : LineType, cmd : Cmd) : ImageRendererModel {
|
||||
this.unloadRenderer(null);
|
||||
let cmdId = cmd.cmdId;
|
||||
let context = {
|
||||
sessionId: this.historyItem.sessionid,
|
||||
screenId: this.historyItem.screenid,
|
||||
windowId: this.historyItem.windowid,
|
||||
cmdId: cmdId,
|
||||
lineId : line.lineid,
|
||||
lineNum: line.linenum
|
||||
};
|
||||
let imageModel = new ImageRendererModel(imageDivElem, context, cmd.getTermOpts(), !cmd.isRunning(), GlobalModel.termFontSize.get());
|
||||
this.renderer = imageModel;
|
||||
return imageModel;
|
||||
}
|
||||
|
||||
unloadRenderer(cmdId : string) : void {
|
||||
if (this.renderer != null) {
|
||||
this.renderer.dispose();
|
||||
this.renderer = null;
|
||||
}
|
||||
}
|
||||
|
||||
getUsedRows(line : LineType, cmd : Cmd, width : number) : number {
|
||||
if (cmd == null) {
|
||||
return 0;
|
||||
}
|
||||
let termOpts = cmd.getTermOpts();
|
||||
if (!termOpts.flexrows) {
|
||||
return termOpts.rows;
|
||||
}
|
||||
let termWrap = this.getRenderer(cmd.cmdId);
|
||||
if (termWrap == null) {
|
||||
let cols = windowWidthToCols(width, GlobalModel.termFontSize.get());
|
||||
let usedRows = GlobalModel.getTUR(this.historyItem.sessionid, cmd.cmdId, cols);
|
||||
if (usedRows != null) {
|
||||
return usedRows;
|
||||
}
|
||||
if (line.contentheight != null && line.contentheight != -1) {
|
||||
return line.contentheight;
|
||||
}
|
||||
return (cmd.isRunning() ? 1 : 0);
|
||||
}
|
||||
return termWrap.getUsedRows();
|
||||
}
|
||||
|
||||
getIsFocused(lineNum : number) : boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getRenderer(cmdId : string) : RendererModel {
|
||||
return this.renderer;
|
||||
}
|
||||
|
||||
getFocusType() : "input" | "cmd" | "cmd-fg" {
|
||||
return "input";
|
||||
}
|
||||
|
||||
getSelectedLine() : number {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const HistoryPageSize = 50;
|
||||
|
||||
class HistoryViewModel {
|
||||
items : OArr<HistoryItem> = mobx.observable.array([], {name: "HistoryItems"});
|
||||
offset : OV<number> = mobx.observable.box(0, {name: "historyview-offset"});
|
||||
searchText : OV<string> = mobx.observable.box("", {name: "historyview-searchtext"});
|
||||
activeSearchText : string = null;
|
||||
selectedItems : OMap<string, boolean> = mobx.observable.map({}, {name: "historyview-selectedItems"});
|
||||
deleteActive : OV<boolean> = mobx.observable.box(false, {name: "historyview-deleteActive"});
|
||||
activeItem : OV<string> = mobx.observable.box(null, {name: "historyview-activeItem"});
|
||||
specialLineContainer : SpecialHistoryViewLineContainer;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
closeView() : void {
|
||||
mobx.action(() => {
|
||||
GlobalModel.activeMainView.set("session");
|
||||
})();
|
||||
}
|
||||
|
||||
setActiveItem(historyId : string) {
|
||||
if (this.activeItem.get() == historyId) {
|
||||
return;
|
||||
}
|
||||
let hitem : HistoryItem = null;
|
||||
if (historyId != null) {
|
||||
for (let i=0; i<this.items.length; i++) {
|
||||
if (this.items[i].historyid == historyId) {
|
||||
hitem = this.items[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mobx.action(() => {
|
||||
if (hitem == null) {
|
||||
this.activeItem.set(null);
|
||||
this.specialLineContainer = null;
|
||||
}
|
||||
else {
|
||||
this.activeItem.set(hitem.historyid);
|
||||
this.specialLineContainer = new SpecialHistoryViewLineContainer(hitem);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
doSelectedDelete() : void {
|
||||
if (!this.deleteActive.get()) {
|
||||
mobx.action(() => {
|
||||
this.deleteActive.set(true);
|
||||
})();
|
||||
setTimeout(this.clearActiveDelete, 2000);
|
||||
return;
|
||||
}
|
||||
console.log("DELETE!");
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clearActiveDelete() : void {
|
||||
mobx.action(() => {
|
||||
this.deleteActive.set(false);
|
||||
})();
|
||||
}
|
||||
|
||||
goPrev() : void {
|
||||
let offset = this.offset.get();
|
||||
offset = offset - HistoryPageSize;
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
GlobalCommandRunner.historyView({offset: offset, searchText: this.activeSearchText});
|
||||
}
|
||||
|
||||
goNext() : void {
|
||||
let offset = this.offset.get();
|
||||
GlobalCommandRunner.historyView({offset: offset+HistoryPageSize, searchText: this.activeSearchText});
|
||||
}
|
||||
|
||||
submitSearch() : void {
|
||||
mobx.action(() => {
|
||||
this.items.replace([]);
|
||||
this.offset.set(0);
|
||||
this.activeSearchText = this.searchText.get();
|
||||
})();
|
||||
GlobalCommandRunner.historyView({offset: 0, searchText: this.activeSearchText});
|
||||
}
|
||||
|
||||
handleDocKeyDown(e : any) : void {
|
||||
if (e.code == "Escape") {
|
||||
e.preventDefault();
|
||||
this.closeView();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
showHistoryView(data : HistoryViewDataType) : void {
|
||||
mobx.action(() => {
|
||||
GlobalModel.activeMainView.set("history");
|
||||
this.items.replace(data.items || []);
|
||||
this.offset.set(data.offset);
|
||||
this.selectedItems.clear();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
class BookmarksModel {
|
||||
bookmarks : OArr<BookmarkType> = mobx.observable.array([], {name: "Bookmarks"});
|
||||
activeBookmark : OV<string> = mobx.observable.box(null, {name: "activeBookmark"});
|
||||
@@ -1851,6 +2050,7 @@ class Model {
|
||||
|
||||
inputModel : InputModel;
|
||||
bookmarksModel : BookmarksModel;
|
||||
historyViewModel : HistoryViewModel;
|
||||
clientData : OV<ClientDataType> = mobx.observable.box(null, {name: "clientData"});
|
||||
|
||||
constructor() {
|
||||
@@ -1861,6 +2061,7 @@ class Model {
|
||||
this.ws.reconnect();
|
||||
this.inputModel = new InputModel();
|
||||
this.bookmarksModel = new BookmarksModel();
|
||||
this.historyViewModel = new HistoryViewModel();
|
||||
let isLocalServerRunning = getApi().getLocalServerStatus();
|
||||
this.localServerRunning = mobx.observable.box(isLocalServerRunning, {name: "model-local-server-running"});
|
||||
this.termFontSize = mobx.computed(() => {
|
||||
@@ -1937,6 +2138,10 @@ class Model {
|
||||
this.bookmarksModel.handleDocKeyDown(e);
|
||||
return;
|
||||
}
|
||||
if (this.activeMainView.get() == "history") {
|
||||
this.historyViewModel.handleDocKeyDown(e);
|
||||
return;
|
||||
}
|
||||
if (e.code == "Escape") {
|
||||
e.preventDefault();
|
||||
let inputModel = this.inputModel;
|
||||
@@ -2200,8 +2405,19 @@ class Model {
|
||||
}
|
||||
this.updateRemotes(update.remotes);
|
||||
}
|
||||
if ("bookmarksview" in update) {
|
||||
this.bookmarksModel.showBookmarksView(update.bookmarks);
|
||||
if ("mainview" in update) {
|
||||
if (update.mainview == "bookmarks") {
|
||||
this.bookmarksModel.showBookmarksView(update.bookmarks);
|
||||
}
|
||||
else if (update.mainview == "session") {
|
||||
this.activeMainView.set("session");
|
||||
}
|
||||
else if (update.mainview == "history") {
|
||||
this.historyViewModel.showHistoryView(update.historyviewdata);
|
||||
}
|
||||
else {
|
||||
console.log("invalid mainview in update:", update.mainview);
|
||||
}
|
||||
}
|
||||
else if ("bookmarks" in update) {
|
||||
this.bookmarksModel.mergeBookmarks(update.bookmarks);
|
||||
@@ -2236,6 +2452,27 @@ class Model {
|
||||
return this.getSessionById(this.activeSessionId.get());
|
||||
}
|
||||
|
||||
getSessionNames() : Record<string,string> {
|
||||
let rtn : Record<string, string> = {};
|
||||
for (let i=0; i<this.sessionList.length; i++) {
|
||||
let session = this.sessionList[i];
|
||||
rtn[session.sessionId] = session.name.get();
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
getScreenNames() : Record<string, string> {
|
||||
let rtn : Record<string, string> = {};
|
||||
for (let i=0; i<this.sessionList.length; i++) {
|
||||
let session = this.sessionList[i];
|
||||
for (let j=0; j<session.screens.length; j++) {
|
||||
let screen = session.screens[j];
|
||||
rtn[screen.screenId] = screen.name.get();
|
||||
}
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
getSessionById(sessionId : string) : Session {
|
||||
if (sessionId == null) {
|
||||
return null;
|
||||
@@ -2501,6 +2738,20 @@ class Model {
|
||||
return null;
|
||||
}
|
||||
|
||||
getRemoteNames() : Record<string, string> {
|
||||
let rtn : Record<string, string> = {};
|
||||
for (let i=0; i<this.remotes.length; i++) {
|
||||
let remote = this.remotes[i];
|
||||
if (!isBlank(remote.remotealias)) {
|
||||
rtn[remote.remoteid] = remote.remotealias;
|
||||
}
|
||||
else {
|
||||
rtn[remote.remoteid] = remote.remotecanonicalname;
|
||||
}
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
getRemoteByName(name : string) : RemoteType {
|
||||
for (let i=0; i<this.remotes.length; i++) {
|
||||
if (this.remotes[i].remotecanonicalname == name || this.remotes[i].remotealias == name) {
|
||||
@@ -2747,6 +2998,17 @@ class CommandRunner {
|
||||
GlobalModel.submitCommand("bookmarks", "show", null, {"nohist": "1"}, true);
|
||||
}
|
||||
|
||||
historyView(params : {offset? : number, searchText? : string}) {
|
||||
let kwargs = {"nohist": "1"};
|
||||
if (params.offset != null) {
|
||||
kwargs["offset"] = String(params.offset);
|
||||
}
|
||||
if (params.searchText != null) {
|
||||
kwargs["text"] = params.searchText;
|
||||
}
|
||||
GlobalModel.submitCommand("history", "viewall", null, kwargs, true);
|
||||
}
|
||||
|
||||
editBookmark(bookmarkId : string, desc : string, cmdstr : string) {
|
||||
let kwargs = {
|
||||
"nohist": "1",
|
||||
@@ -2820,5 +3082,6 @@ GlobalModel = (window as any).GlobalModel;
|
||||
GlobalCommandRunner = (window as any).GlobalCommandRunner;
|
||||
|
||||
export {Model, Session, Window, GlobalModel, GlobalCommandRunner, Cmd, Screen, ScreenWindow, riToRPtr, windowWidthToCols, windowHeightToRows, termWidthFromCols, termHeightFromRows, getPtyData, getRemotePtyData};
|
||||
export type {LineContainerModel};
|
||||
|
||||
|
||||
|
||||
+235
-22
@@ -151,19 +151,11 @@ body::-webkit-scrollbar {
|
||||
}
|
||||
}
|
||||
|
||||
.history-view {
|
||||
.history-title {
|
||||
margin: 10px 0 10px 15px;
|
||||
.mono-font(1.5rem);
|
||||
color: @term-bright-white;
|
||||
}
|
||||
}
|
||||
|
||||
.bookmarks-view {
|
||||
.alt-view {
|
||||
background-color: #222;
|
||||
overflow-y: auto;
|
||||
|
||||
.bookmarks-title {
|
||||
.alt-title {
|
||||
margin: 20px 10px 0px 5px;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 12px;
|
||||
@@ -186,18 +178,7 @@ body::-webkit-scrollbar {
|
||||
}
|
||||
}
|
||||
|
||||
.bookmarks-list {
|
||||
color: white;
|
||||
margin: 4px 10px 5px 5px;
|
||||
|
||||
.no-bookmarks {
|
||||
color: @term-white;
|
||||
padding: 30px 10px 35px 10px;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
}
|
||||
|
||||
.bookmarks-help {
|
||||
.alt-help {
|
||||
color: @term-white;
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
@@ -210,6 +191,238 @@ body::-webkit-scrollbar {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.history-view {
|
||||
color: #ccc;
|
||||
|
||||
.close-button {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 10px;
|
||||
|
||||
.history-title {
|
||||
.mono-font(1.5rem);
|
||||
font-weight: bold;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
|
||||
i {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.history-search {
|
||||
flex-grow: 1;
|
||||
margin-top: 5px;
|
||||
margin-left: 15px;
|
||||
.field {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.control-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 5px;
|
||||
margin-right: 10px;
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
align-items: center;
|
||||
|
||||
.control-checkbox {
|
||||
cursor: pointer;
|
||||
color: #777;
|
||||
font-size: 18px;
|
||||
width: 24px;
|
||||
margin-left: 14px;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.control-button {
|
||||
cursor: pointer;
|
||||
color: #aaa;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
|
||||
&.is-disabled {
|
||||
cursor: default;
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.delete-button.is-active:hover {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.showing-text {
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.showing-btn {
|
||||
padding: 0 5px 0 5px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
|
||||
&.is-disabled {
|
||||
cursor: default;
|
||||
color: #777;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-spacer {
|
||||
width: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.history-table {
|
||||
margin: 0px 10px 10px 10px;
|
||||
table-layout: fixed;
|
||||
border-top: 2px solid #ccc;
|
||||
|
||||
tr.active-history-item {
|
||||
td {
|
||||
padding: 10px;
|
||||
background-color: blue;
|
||||
}
|
||||
}
|
||||
|
||||
tr.history-item {
|
||||
padding: 0 10px 0 10px;
|
||||
display: flex;
|
||||
border-top: 1px solid #333;
|
||||
align-items: center;
|
||||
|
||||
&.is-selected {
|
||||
background-color: #003;
|
||||
|
||||
td.cmdstr {
|
||||
background-color: #000017;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-selected:hover {
|
||||
background-color: #336;
|
||||
|
||||
td.cmdstr {
|
||||
background-color: #113;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #333;
|
||||
|
||||
td.cmdstr {
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
td.bookmark i {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
td.selectbox {
|
||||
flex: 0 0 auto;
|
||||
flex-basis: 24px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
td.bookmark {
|
||||
flex: 0 0 auto;
|
||||
flex-basis: 20px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
td.ts {
|
||||
font-size: 12px;
|
||||
flex: 0 0 auto;
|
||||
flex-basis: 65px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.session {
|
||||
font-size: 12px;
|
||||
flex: 0 0 auto;
|
||||
flex-basis: 120px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
td.remote {
|
||||
.mono-font(12px);
|
||||
flex: 0 0 auto;
|
||||
flex-basis: 150px;
|
||||
text-overflow: ellipsis;
|
||||
padding-right: 5px;
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
td.cmdstr {
|
||||
.mono-font(12px);
|
||||
color: white;
|
||||
background-color: black;
|
||||
flex: 1 0 auto;
|
||||
padding-left: 20px;
|
||||
border-radius: 3px;
|
||||
white-space: pre;
|
||||
max-height: 64px;
|
||||
overflow-y: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bookmarks-view {
|
||||
.bookmarks-list {
|
||||
color: white;
|
||||
margin: 4px 10px 5px 5px;
|
||||
|
||||
.no-bookmarks {
|
||||
color: @term-white;
|
||||
padding: 30px 10px 35px 10px;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
}
|
||||
|
||||
.bookmark {
|
||||
border-bottom: 1px solid #777;
|
||||
|
||||
+30
-2
@@ -283,9 +283,16 @@ type ModelUpdateType = {
|
||||
remotes? : RemoteType[],
|
||||
history? : HistoryInfoType,
|
||||
connect? : boolean,
|
||||
bookmarksview? : boolean,
|
||||
mainview? : string,
|
||||
bookmarks? : BookmarkType[],
|
||||
clientdata? : ClientDataType,
|
||||
historyviewdata? : HistoryViewDataType,
|
||||
};
|
||||
|
||||
type HistoryViewDataType = {
|
||||
totalcount : number,
|
||||
offset : number,
|
||||
items : HistoryItem[],
|
||||
};
|
||||
|
||||
type BookmarkType = {
|
||||
@@ -392,4 +399,25 @@ type ClientDataType = {
|
||||
feopts : FeOptsType;
|
||||
};
|
||||
|
||||
export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDataType, ScreenDataType, ScreenOptsType, ScreenWindowType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, RemotePtrType, UIContextType, HistoryInfoType, HistoryQueryOpts, WatchScreenPacketType, TermWinSize, FeInputPacketType, RemoteInputPacketType, RemoteEditType, FeStateType, ContextMenuOpts, RendererContext, WindowSize, RendererModel, PtyDataType, BookmarkType, ClientDataType};
|
||||
type PlaybookType = {
|
||||
playbookid : string,
|
||||
playbookname : string,
|
||||
description : string,
|
||||
entryids : string[],
|
||||
entries : PlaybookEntryType[],
|
||||
};
|
||||
|
||||
type PlaybookEntryType = {
|
||||
entryid : string,
|
||||
playbookid : string,
|
||||
alias : string,
|
||||
cmdstr : string,
|
||||
description : string,
|
||||
createdts : number,
|
||||
updatedts : number,
|
||||
remove : boolean,
|
||||
};
|
||||
|
||||
type RenderModeType = "normal" | "collapsed";
|
||||
|
||||
export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDataType, ScreenDataType, ScreenOptsType, ScreenWindowType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, RemotePtrType, UIContextType, HistoryInfoType, HistoryQueryOpts, WatchScreenPacketType, TermWinSize, FeInputPacketType, RemoteInputPacketType, RemoteEditType, FeStateType, ContextMenuOpts, RendererContext, WindowSize, RendererModel, PtyDataType, BookmarkType, ClientDataType, PlaybookType, PlaybookEntryType, HistoryViewDataType, RenderModeType};
|
||||
|
||||
Reference in New Issue
Block a user