working on history inbox view

This commit is contained in:
sawka
2023-03-02 00:33:10 -08:00
parent c3d07223f7
commit adfec86d8b
7 changed files with 1700 additions and 916 deletions
+3 -3
View File
@@ -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
View File
@@ -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};
+847
View File
File diff suppressed because it is too large Load Diff
+71 -886
View File
File diff suppressed because it is too large Load Diff
+266 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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};