mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea253c33ae | |||
| 53de138832 | |||
| 75778963c5 | |||
| 89906d21d4 | |||
| 747a2b784a | |||
| 84e7605e36 | |||
| 839e338dad | |||
| 771046637d | |||
| 8dc3b3b0c1 | |||
| 0a8c8221fd | |||
| 38c6e8f5f8 | |||
| def90a0493 | |||
| e2d10cd807 | |||
| 26240bea97 | |||
| fa9a0bd228 | |||
| fa2c684c0e | |||
| 750e8bc9f7 | |||
| f781e358e5 | |||
| 98f6b84d3e |
@@ -1,13 +1,13 @@
|
||||
import * as React from "react";
|
||||
import { GlobalModel } from "../../../models";
|
||||
import { Choose, When, If } from "tsx-control-statements/components";
|
||||
import { Choose, When, If } from "tsx-control-statements";
|
||||
import { Modal, PasswordField, Markdown } from "../elements";
|
||||
import { UserInputRequest } from "../../../types/types";
|
||||
|
||||
import "./userinput.less";
|
||||
|
||||
export const UserInputModal = (userInputRequest: UserInputRequest) => {
|
||||
const [responseText, setResponseText] = React.useState("");
|
||||
const [responseText, setResponseText] = React.useState(null);
|
||||
const [countdown, setCountdown] = React.useState(Math.floor(userInputRequest.timeoutms / 1000));
|
||||
|
||||
const closeModal = React.useCallback(() => {
|
||||
|
||||
@@ -54,8 +54,6 @@
|
||||
}
|
||||
|
||||
.remote-detail {
|
||||
width: 100%;
|
||||
|
||||
.settings-field {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -93,9 +91,8 @@
|
||||
}
|
||||
|
||||
.terminal-wrapper {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
.terminal-connectelem {
|
||||
height: 163px !important; // Needed to override plugin height
|
||||
@@ -114,6 +111,7 @@
|
||||
|
||||
.xterm-screen {
|
||||
padding: 10px;
|
||||
width: 541px !important; // Needed to override plugin width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@ import * as T from "../../../types/types";
|
||||
import { Modal, Tooltip, Button, Status } from "../elements";
|
||||
import * as util from "../../../util/util";
|
||||
import * as textmeasure from "../../../util/textmeasure";
|
||||
import * as appconst from "../../appconst";
|
||||
|
||||
import "./viewremoteconndetail.less";
|
||||
|
||||
const RemotePtyRows = 9;
|
||||
const RemotePtyCols = 80;
|
||||
|
||||
@mobxReact.observer
|
||||
class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
termRef: React.RefObject<any> = React.createRef();
|
||||
@@ -291,7 +293,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
let model = this.model;
|
||||
let isTermFocused = this.model.remoteTermWrapFocus.get();
|
||||
let termFontSize = GlobalModel.termFontSize.get();
|
||||
let termWidth = textmeasure.termWidthFromCols(appconst.RemotePtyCols, termFontSize);
|
||||
let termWidth = textmeasure.termWidthFromCols(RemotePtyCols, termFontSize);
|
||||
let remoteAliasText = util.isBlank(remote.remotealias) ? "(none)" : remote.remotealias;
|
||||
let selectedRemoteStatus = this.getSelectedRemote().status;
|
||||
|
||||
@@ -369,7 +371,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
ref={this.termRef}
|
||||
data-remoteid={remote.remoteid}
|
||||
style={{
|
||||
height: textmeasure.termHeightFromRows(appconst.RemotePtyRows, termFontSize),
|
||||
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize),
|
||||
width: termWidth,
|
||||
}}
|
||||
></div>
|
||||
|
||||
+15
-10
@@ -13,10 +13,10 @@ import {
|
||||
HistoryQueryOpts,
|
||||
HistoryTypeStrs,
|
||||
OpenAICmdInfoChatMessageType,
|
||||
OV,
|
||||
StrWithPos,
|
||||
} from "../types/types";
|
||||
import { StrWithPos } from "../types/types";
|
||||
import * as appconst from "../app/appconst";
|
||||
import { OV } from "../types/types";
|
||||
import { Model } from "./model";
|
||||
import { GlobalCommandRunner } from "./global";
|
||||
|
||||
@@ -207,6 +207,7 @@ class InputModel {
|
||||
this.historyQueryOpts.set(opts);
|
||||
let bestIndex = this.findBestNewIndex(oldItem);
|
||||
setTimeout(() => this.setHistoryIndex(bestIndex, true), 10);
|
||||
return;
|
||||
})();
|
||||
}
|
||||
|
||||
@@ -623,17 +624,13 @@ class InputModel {
|
||||
}
|
||||
|
||||
openAIAssistantChat(): void {
|
||||
mobx.action(() => {
|
||||
this.aIChatShow.set(true);
|
||||
this.setAIChatFocus();
|
||||
})();
|
||||
this.aIChatShow.set(true);
|
||||
this.setAIChatFocus();
|
||||
}
|
||||
|
||||
closeAIAssistantChat(): void {
|
||||
mobx.action(() => {
|
||||
this.aIChatShow.set(false);
|
||||
this.giveFocus();
|
||||
})();
|
||||
this.aIChatShow.set(false);
|
||||
this.giveFocus();
|
||||
}
|
||||
|
||||
clearAIAssistantChat(): void {
|
||||
@@ -724,6 +721,14 @@ class InputModel {
|
||||
setCurLine(val: string): void {
|
||||
let hidx = this.historyIndex.get();
|
||||
mobx.action(() => {
|
||||
// if (val == "\" ") {
|
||||
// this.setInputMode("comment");
|
||||
// val = "";
|
||||
// }
|
||||
// if (val == "//") {
|
||||
// this.setInputMode("global");
|
||||
// val = "";
|
||||
// }
|
||||
if (this.modHistory.length <= hidx) {
|
||||
this.modHistory.length = hidx + 1;
|
||||
}
|
||||
|
||||
+247
-294
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,9 @@ import { GlobalCommandRunner } from "./global";
|
||||
import { Model } from "./model";
|
||||
import { getTermPtyData } from "../util/modelutil";
|
||||
|
||||
const RemotePtyRows = 8; // also in main.tsx
|
||||
const RemotePtyCols = 80;
|
||||
|
||||
class RemotesModel {
|
||||
globalModel: Model;
|
||||
selectedRemoteId: OV<string> = mobx.observable.box(null, {
|
||||
@@ -177,14 +180,14 @@ class RemotesModel {
|
||||
return;
|
||||
}
|
||||
let termOpts = {
|
||||
rows: appconst.RemotePtyRows,
|
||||
cols: appconst.RemotePtyCols,
|
||||
rows: RemotePtyRows,
|
||||
cols: RemotePtyCols,
|
||||
flexrows: false,
|
||||
maxptysize: 64 * 1024,
|
||||
};
|
||||
let termWrap = new TermWrap(elem, {
|
||||
termContext: { remoteId: remoteId },
|
||||
usedRows: appconst.RemotePtyRows,
|
||||
usedRows: RemotePtyRows,
|
||||
termOpts: termOpts,
|
||||
winSize: null,
|
||||
keyHandler: (e, termWrap) => {
|
||||
|
||||
@@ -139,7 +139,7 @@ class ScreenLines {
|
||||
return;
|
||||
}
|
||||
let lineIdx = 0;
|
||||
for (lineIdx; lineIdx < lines.length; lineIdx++) {
|
||||
for (lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
||||
let lineId = lines[lineIdx].lineid;
|
||||
let curTs = lines[lineIdx].ts;
|
||||
if (lineId == line.lineid) {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
.terminal-wrapper {
|
||||
.xterm-viewport {
|
||||
overflow: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
&:hover .xterm-viewport,
|
||||
&:focus-within .xterm-viewport {
|
||||
overflow: auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-36
@@ -29,6 +29,7 @@ type SessionDataType = {
|
||||
|
||||
// for updates
|
||||
remove?: boolean;
|
||||
full?: boolean;
|
||||
};
|
||||
|
||||
type LineStateType = { [k: string]: any };
|
||||
@@ -91,6 +92,7 @@ type ScreenDataType = {
|
||||
anchor: { anchorline: number; anchoroffset: number };
|
||||
|
||||
// for updates
|
||||
full?: boolean;
|
||||
remove?: boolean;
|
||||
};
|
||||
|
||||
@@ -258,11 +260,6 @@ type CmdDataType = {
|
||||
restarted?: boolean;
|
||||
};
|
||||
|
||||
type LineUpdateType = {
|
||||
line: LineType;
|
||||
cmd: CmdDataType;
|
||||
};
|
||||
|
||||
type PtyDataUpdateType = {
|
||||
screenid: string;
|
||||
lineid: string;
|
||||
@@ -312,47 +309,30 @@ type ScreenNumRunningCommandsUpdateType = {
|
||||
num: number;
|
||||
};
|
||||
|
||||
type ConnectUpdateType = {
|
||||
sessions: SessionDataType[];
|
||||
screens: ScreenDataType[];
|
||||
remotes: RemoteType[];
|
||||
screenstatusindicators: ScreenStatusIndicatorUpdateType[];
|
||||
screennumrunningcommands: ScreenNumRunningCommandsUpdateType[];
|
||||
activesessionid: string;
|
||||
};
|
||||
|
||||
type BookmarksUpdateType = {
|
||||
bookmarks: BookmarkType[];
|
||||
selectedbookmark: string;
|
||||
};
|
||||
|
||||
type MainViewUpdateType = {
|
||||
mainview: string;
|
||||
historyview?: HistoryViewDataType;
|
||||
bookmarksview?: BookmarksUpdateType;
|
||||
};
|
||||
|
||||
type ModelUpdateType = {
|
||||
interactive: boolean;
|
||||
session?: SessionDataType;
|
||||
sessions?: SessionDataType[];
|
||||
activesessionid?: string;
|
||||
screen?: ScreenDataType;
|
||||
screens?: ScreenDataType[];
|
||||
screenlines?: ScreenLinesType;
|
||||
line?: LineUpdateType;
|
||||
line?: LineType;
|
||||
lines?: LineType[];
|
||||
cmd?: CmdDataType;
|
||||
info?: InfoType;
|
||||
cmdline?: StrWithPos;
|
||||
remote?: RemoteType;
|
||||
remotes?: RemoteType[];
|
||||
history?: HistoryInfoType;
|
||||
connect?: ConnectUpdateType;
|
||||
mainview?: MainViewUpdateType;
|
||||
bookmarks?: BookmarksUpdateType;
|
||||
connect?: boolean;
|
||||
mainview?: string;
|
||||
bookmarks?: BookmarkType[];
|
||||
selectedbookmark?: string;
|
||||
clientdata?: ClientDataType;
|
||||
historyviewdata?: HistoryViewDataType;
|
||||
remoteview?: RemoteViewType;
|
||||
openaicmdinfochat?: OpenAICmdInfoChatMessageType[];
|
||||
alertmessage?: AlertMessageType;
|
||||
screenstatusindicator?: ScreenStatusIndicatorUpdateType;
|
||||
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType;
|
||||
screenstatusindicators?: ScreenStatusIndicatorUpdateType[];
|
||||
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType[];
|
||||
userinputrequest?: UserInputRequest;
|
||||
};
|
||||
|
||||
@@ -435,7 +415,7 @@ type ContextMenuOpts = {
|
||||
showCut?: boolean;
|
||||
};
|
||||
|
||||
type UpdateMessage = PtyDataUpdateType | ModelUpdateType[];
|
||||
type UpdateMessage = PtyDataUpdateType | ModelUpdateType;
|
||||
|
||||
type RendererContext = {
|
||||
screenId: string;
|
||||
@@ -886,7 +866,6 @@ export type {
|
||||
CmdInputTextPacketType,
|
||||
OpenAICmdInfoChatMessageType,
|
||||
ScreenStatusIndicatorUpdateType,
|
||||
ScreenNumRunningCommandsUpdateType,
|
||||
OV,
|
||||
OArr,
|
||||
OMap,
|
||||
|
||||
+69
-53
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// Copyright 2023, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import * as mobx from "mobx";
|
||||
@@ -17,7 +17,7 @@ function isBlank(s: string): boolean {
|
||||
}
|
||||
|
||||
function handleNotOkResp(resp: any, url: URL): Promise<any> {
|
||||
const errMsg = sprintf(
|
||||
let errMsg = sprintf(
|
||||
"Bad status code response from fetch '%s': code=%d %s",
|
||||
url.toString(),
|
||||
resp.status,
|
||||
@@ -41,18 +41,18 @@ function handleNotOkResp(resp: any, url: URL): Promise<any> {
|
||||
}
|
||||
|
||||
function fetchJsonData(resp: any, ctErr: boolean): Promise<any> {
|
||||
const contentType = resp.headers.get("Content-Type");
|
||||
if (contentType?.startsWith("application/json")) {
|
||||
let contentType = resp.headers.get("Content-Type");
|
||||
if (contentType != null && contentType.startsWith("application/json")) {
|
||||
return resp.text().then((textData) => {
|
||||
let rtnData: any = null;
|
||||
try {
|
||||
rtnData = JSON.parse(textData);
|
||||
} catch (err) {
|
||||
const errMsg = sprintf("Unparseable JSON: " + err.message);
|
||||
const rtnErr = new Error(errMsg);
|
||||
let errMsg = sprintf("Unparseable JSON: " + err.message);
|
||||
let rtnErr = new Error(errMsg);
|
||||
throw rtnErr;
|
||||
}
|
||||
if (rtnData?.error) {
|
||||
if (rtnData != null && rtnData.error) {
|
||||
throw new Error(rtnData.error);
|
||||
}
|
||||
return rtnData;
|
||||
@@ -67,23 +67,23 @@ function handleJsonFetchResponse(url: URL, resp: any): Promise<any> {
|
||||
if (!resp.ok) {
|
||||
return handleNotOkResp(resp, url);
|
||||
}
|
||||
const rtnData = fetchJsonData(resp, true);
|
||||
let rtnData = fetchJsonData(resp, true);
|
||||
return rtnData;
|
||||
}
|
||||
|
||||
function base64ToString(b64: string): string {
|
||||
const stringBytes = base64.toByteArray(b64);
|
||||
let stringBytes = base64.toByteArray(b64);
|
||||
return new TextDecoder().decode(stringBytes);
|
||||
}
|
||||
|
||||
function stringToBase64(input: string): string {
|
||||
const stringBytes = new TextEncoder().encode(input);
|
||||
let stringBytes = new TextEncoder().encode(input);
|
||||
return base64.fromByteArray(stringBytes);
|
||||
}
|
||||
|
||||
function base64ToArray(b64: string): Uint8Array {
|
||||
const rawStr = atob(b64);
|
||||
const rtnArr = new Uint8Array(new ArrayBuffer(rawStr.length));
|
||||
let rawStr = atob(b64);
|
||||
let rtnArr = new Uint8Array(new ArrayBuffer(rawStr.length));
|
||||
for (let i = 0; i < rawStr.length; i++) {
|
||||
rtnArr[i] = rawStr.charCodeAt(i);
|
||||
}
|
||||
@@ -92,6 +92,7 @@ function base64ToArray(b64: string): Uint8Array {
|
||||
|
||||
interface IDataType {
|
||||
remove?: boolean;
|
||||
full?: boolean;
|
||||
}
|
||||
|
||||
interface IObjType<DataType> {
|
||||
@@ -112,28 +113,31 @@ function genMergeSimpleData<T extends ISimpleDataType>(
|
||||
if (dataArr == null || dataArr.length == 0) {
|
||||
return;
|
||||
}
|
||||
const objMap: Record<string, T> = {};
|
||||
for (const obj of objs) {
|
||||
const id = idFn(obj);
|
||||
let objMap: Record<string, T> = {};
|
||||
for (let i = 0; i < objs.length; i++) {
|
||||
let obj = objs[i];
|
||||
let id = idFn(obj);
|
||||
objMap[id] = obj;
|
||||
}
|
||||
for (const dataItem of dataArr) {
|
||||
for (let i = 0; i < dataArr.length; i++) {
|
||||
let dataItem = dataArr[i];
|
||||
if (dataItem == null) {
|
||||
console.log("genMergeSimpleData, null item");
|
||||
console.trace();
|
||||
}
|
||||
const id = idFn(dataItem);
|
||||
let id = idFn(dataItem);
|
||||
if (dataItem.remove) {
|
||||
delete objMap[id];
|
||||
continue;
|
||||
} else {
|
||||
objMap[id] = dataItem;
|
||||
}
|
||||
}
|
||||
const newObjs = Object.values(objMap);
|
||||
let newObjs = Object.values(objMap);
|
||||
if (sortIdxFn) {
|
||||
newObjs.sort((a, b) => {
|
||||
const astr = sortIdxFn(a);
|
||||
const bstr = sortIdxFn(b);
|
||||
let astr = sortIdxFn(a);
|
||||
let bstr = sortIdxFn(b);
|
||||
return astr.localeCompare(bstr);
|
||||
});
|
||||
}
|
||||
@@ -151,18 +155,20 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
|
||||
if (dataArr == null || dataArr.length == 0) {
|
||||
return;
|
||||
}
|
||||
const objMap: Record<string, ObjType> = {};
|
||||
for (const obj of objs) {
|
||||
const id = objIdFn(obj);
|
||||
let objMap: Record<string, ObjType> = {};
|
||||
for (let i = 0; i < objs.length; i++) {
|
||||
let obj = objs[i];
|
||||
let id = objIdFn(obj);
|
||||
objMap[id] = obj;
|
||||
}
|
||||
for (const dataItem of dataArr) {
|
||||
for (let i = 0; i < dataArr.length; i++) {
|
||||
let dataItem = dataArr[i];
|
||||
if (dataItem == null) {
|
||||
console.log("genMergeData, null item");
|
||||
console.trace();
|
||||
continue;
|
||||
}
|
||||
const id = dataIdFn(dataItem);
|
||||
let id = dataIdFn(dataItem);
|
||||
let obj = objMap[id];
|
||||
if (dataItem.remove) {
|
||||
if (obj != null) {
|
||||
@@ -172,13 +178,17 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
|
||||
continue;
|
||||
}
|
||||
if (obj == null) {
|
||||
if (!dataItem.full) {
|
||||
console.log("cannot create object, dataitem is not full", objs, dataItem);
|
||||
continue;
|
||||
}
|
||||
obj = ctorFn(dataItem);
|
||||
objMap[id] = obj;
|
||||
continue;
|
||||
}
|
||||
obj.mergeData(dataItem);
|
||||
}
|
||||
const newObjs = Object.values(objMap);
|
||||
let newObjs = Object.values(objMap);
|
||||
if (sortIdxFn) {
|
||||
newObjs.sort((a, b) => {
|
||||
return sortIdxFn(a) - sortIdxFn(b);
|
||||
@@ -194,17 +204,18 @@ function genMergeDataMap<ObjType extends IObjType<DataType>, DataType extends ID
|
||||
dataIdFn: (data: DataType) => string,
|
||||
ctorFn: (data: DataType) => ObjType
|
||||
): { added: string[]; removed: string[] } {
|
||||
const rtn: { added: string[]; removed: string[] } = { added: [], removed: [] };
|
||||
let rtn: { added: string[]; removed: string[] } = { added: [], removed: [] };
|
||||
if (dataArr == null || dataArr.length == 0) {
|
||||
return rtn;
|
||||
}
|
||||
for (const dataItem of dataArr) {
|
||||
for (let i = 0; i < dataArr.length; i++) {
|
||||
let dataItem = dataArr[i];
|
||||
if (dataItem == null) {
|
||||
console.log("genMergeDataMap, null item");
|
||||
console.trace();
|
||||
continue;
|
||||
}
|
||||
const id = dataIdFn(dataItem);
|
||||
let id = dataIdFn(dataItem);
|
||||
let obj = objMap.get(id);
|
||||
if (dataItem.remove) {
|
||||
if (obj != null) {
|
||||
@@ -215,6 +226,10 @@ function genMergeDataMap<ObjType extends IObjType<DataType>, DataType extends 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);
|
||||
@@ -247,23 +262,23 @@ function incObs(inum: mobx.IObservableValue<number>) {
|
||||
|
||||
// @check:font
|
||||
function loadFonts() {
|
||||
const jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
||||
let jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
||||
style: "normal",
|
||||
weight: "400",
|
||||
});
|
||||
const jbmFont200 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-200.woff2')", {
|
||||
let jbmFont200 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-200.woff2')", {
|
||||
style: "normal",
|
||||
weight: "200",
|
||||
});
|
||||
const jbmFont700 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-700.woff2')", {
|
||||
let jbmFont700 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-700.woff2')", {
|
||||
style: "normal",
|
||||
weight: "700",
|
||||
});
|
||||
const faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
||||
let faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
||||
style: "normal",
|
||||
weight: "normal",
|
||||
});
|
||||
const docFonts: any = document.fonts; // work around ts typing issue
|
||||
let docFonts: any = document.fonts; // work around ts typing issue
|
||||
docFonts.add(jbmFontNormal);
|
||||
docFonts.add(jbmFont200);
|
||||
docFonts.add(jbmFont700);
|
||||
@@ -281,13 +296,13 @@ function getTodayStr(): string {
|
||||
}
|
||||
|
||||
function getYesterdayStr(): string {
|
||||
const d = new Date();
|
||||
let d = new Date();
|
||||
d.setDate(d.getDate() - 1);
|
||||
return getDateStr(d);
|
||||
}
|
||||
|
||||
function getDateStr(d: Date): string {
|
||||
const yearStr = String(d.getFullYear());
|
||||
let yearStr = String(d.getFullYear());
|
||||
let monthStr = String(d.getMonth() + 1);
|
||||
if (monthStr.length == 1) {
|
||||
monthStr = "0" + monthStr;
|
||||
@@ -296,30 +311,31 @@ function getDateStr(d: Date): string {
|
||||
if (dayStr.length == 1) {
|
||||
dayStr = "0" + dayStr;
|
||||
}
|
||||
const dowStr = DOW_STRS[d.getDay()];
|
||||
let dowStr = DOW_STRS[d.getDay()];
|
||||
return dowStr + " " + yearStr + "-" + monthStr + "-" + dayStr;
|
||||
}
|
||||
|
||||
function getRemoteConnVal(r: RemoteType): number {
|
||||
switch (r.status) {
|
||||
case "connected":
|
||||
return 1;
|
||||
case "connecting":
|
||||
return 2;
|
||||
case "disconnected":
|
||||
return 3;
|
||||
case "error":
|
||||
return 4;
|
||||
default:
|
||||
return 5;
|
||||
if (r.status == "connected") {
|
||||
return 1;
|
||||
}
|
||||
if (r.status == "connecting") {
|
||||
return 2;
|
||||
}
|
||||
if (r.status == "disconnected") {
|
||||
return 3;
|
||||
}
|
||||
if (r.status == "error") {
|
||||
return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
function sortAndFilterRemotes(origRemotes: RemoteType[]): RemoteType[] {
|
||||
const remotes = origRemotes.filter((r) => !r.archived);
|
||||
let remotes = origRemotes.filter((r) => !r.archived);
|
||||
remotes.sort((a, b) => {
|
||||
const connValA = getRemoteConnVal(a);
|
||||
const connValB = getRemoteConnVal(b);
|
||||
let connValA = getRemoteConnVal(a);
|
||||
let connValB = getRemoteConnVal(b);
|
||||
if (connValA != connValB) {
|
||||
return connValA - connValB;
|
||||
}
|
||||
@@ -356,7 +372,7 @@ function openLink(url: string): void {
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
function getColorRGB(colorInput: string) {
|
||||
function getColorRGB(colorInput) {
|
||||
const tempElement = document.createElement("div");
|
||||
tempElement.style.color = colorInput;
|
||||
document.body.appendChild(tempElement);
|
||||
@@ -383,7 +399,7 @@ function getRemoteName(remote: RemoteType): string {
|
||||
if (remote == null) {
|
||||
return "";
|
||||
}
|
||||
const { remotealias, remotecanonicalname } = remote;
|
||||
let { remotealias, remotecanonicalname } = remote;
|
||||
return remotealias ? `${remotealias} [${remotecanonicalname}]` : remotecanonicalname;
|
||||
}
|
||||
|
||||
|
||||
@@ -257,7 +257,10 @@ func (z zshShellApi) MakeRcFileStr(pk *packet.RunPacketType) string {
|
||||
}
|
||||
rcBuf.WriteString("\n")
|
||||
}
|
||||
// do NOT unset ZDOTDIR, otherwise initialization will start to read initialization files from ~/ again
|
||||
if shellenv.FindVarDecl(varDecls, "ZDOTDIR") == nil {
|
||||
rcBuf.WriteString("unset ZDOTDIR\n")
|
||||
rcBuf.WriteString("\n")
|
||||
}
|
||||
for _, varName := range ZshUnsetVars {
|
||||
rcBuf.WriteString("unset " + shellescape.Quote(varName) + "\n")
|
||||
}
|
||||
|
||||
+286
-245
File diff suppressed because it is too large
Load Diff
@@ -66,8 +66,9 @@ func CheckNewRelease(ctx context.Context, force bool) (ReleaseCheckResult, error
|
||||
return Failure, fmt.Errorf("error getting updated client data: %w", err)
|
||||
}
|
||||
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *clientData)
|
||||
update := &sstore.ModelUpdate{
|
||||
ClientData: clientData,
|
||||
}
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
|
||||
return Success, nil
|
||||
|
||||
@@ -678,19 +678,18 @@ func (msh *MShellProc) GetRemoteRuntimeState() RemoteRuntimeState {
|
||||
|
||||
func (msh *MShellProc) NotifyRemoteUpdate() {
|
||||
rstate := msh.GetRemoteRuntimeState()
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, rstate)
|
||||
update := &sstore.ModelUpdate{Remotes: []RemoteRuntimeState{rstate}}
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
}
|
||||
|
||||
func GetAllRemoteRuntimeState() []*RemoteRuntimeState {
|
||||
func GetAllRemoteRuntimeState() []RemoteRuntimeState {
|
||||
GlobalStore.Lock.Lock()
|
||||
defer GlobalStore.Lock.Unlock()
|
||||
|
||||
var rtn []*RemoteRuntimeState
|
||||
var rtn []RemoteRuntimeState
|
||||
for _, proc := range GlobalStore.Map {
|
||||
state := proc.GetRemoteRuntimeState()
|
||||
rtn = append(rtn, &state)
|
||||
rtn = append(rtn, state)
|
||||
}
|
||||
return rtn
|
||||
}
|
||||
@@ -1998,8 +1997,7 @@ func (msh *MShellProc) notifyHangups_nolock() {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *cmd)
|
||||
update := &sstore.ModelUpdate{Cmd: cmd}
|
||||
sstore.MainBus.SendScreenUpdate(ck.GetGroupId(), update)
|
||||
go pushNumRunningCmdsUpdate(&ck, -1)
|
||||
}
|
||||
@@ -2029,7 +2027,7 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
if screen != nil {
|
||||
sstore.AddUpdate(update, *screen)
|
||||
update.Screens = []*sstore.ScreenType{screen}
|
||||
}
|
||||
rct := msh.GetRunningCmd(donePk.CK)
|
||||
var statePtr *sstore.ShellStatePtr
|
||||
@@ -2041,7 +2039,7 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
if remoteInst != nil {
|
||||
sstore.AddUpdate(update, sstore.MakeSessionUpdateForRemote(rct.SessionId, remoteInst))
|
||||
update.Sessions = sstore.MakeSessionsUpdateForRemote(rct.SessionId, remoteInst)
|
||||
}
|
||||
statePtr = &sstore.ShellStatePtr{BaseHash: donePk.FinalState.GetHashVal(false)}
|
||||
} else if donePk.FinalStateDiff != nil && rct != nil {
|
||||
@@ -2061,7 +2059,7 @@ func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
// fall-through (nothing to do)
|
||||
}
|
||||
if remoteInst != nil {
|
||||
sstore.AddUpdate(update, sstore.MakeSessionUpdateForRemote(rct.SessionId, remoteInst))
|
||||
update.Sessions = sstore.MakeSessionsUpdateForRemote(rct.SessionId, remoteInst)
|
||||
}
|
||||
diffHashArr := append(([]string)(nil), donePk.FinalStateDiff.DiffHashArr...)
|
||||
diffHashArr = append(diffHashArr, donePk.FinalStateDiff.GetHashVal(false))
|
||||
@@ -2104,10 +2102,9 @@ func (msh *MShellProc) handleCmdFinalPacket(finalPk *packet.CmdFinalPacketType)
|
||||
log.Printf("error getting cmd(2) in handleCmdFinalPacket (not found)\n")
|
||||
return
|
||||
}
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *rtnCmd)
|
||||
update := &sstore.ModelUpdate{Cmd: rtnCmd}
|
||||
if screen != nil {
|
||||
sstore.AddUpdate(update, *screen)
|
||||
update.Screens = []*sstore.ScreenType{screen}
|
||||
}
|
||||
go pushNumRunningCmdsUpdate(&finalPk.CK, -1)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
@@ -2175,9 +2172,7 @@ func (msh *MShellProc) makeHandleCmdFinalPacketClosure(finalPk *packet.CmdFinalP
|
||||
|
||||
func sendScreenUpdates(screens []*sstore.ScreenType) {
|
||||
for _, screen := range screens {
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, *screen)
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
sstore.MainBus.SendUpdate(&sstore.ModelUpdate{Screens: []*sstore.ScreenType{screen}})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -388,12 +388,11 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
|
||||
"%s\n\n"+
|
||||
"**Offending Keys** \n"+
|
||||
"%s", key.Type(), correctKeyFingerprint, strings.Join(bulletListKnownHosts, " \n"), strings.Join(offendingKeysFmt, " \n"))
|
||||
update := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(update, sstore.AlertMessageType{
|
||||
update := &sstore.ModelUpdate{AlertMessage: &sstore.AlertMessageType{
|
||||
Markdown: true,
|
||||
Title: "Known Hosts Key Changed",
|
||||
Message: alertText,
|
||||
})
|
||||
}}
|
||||
sstore.MainBus.SendUpdate(update)
|
||||
return fmt.Errorf("remote host identification has changed")
|
||||
}
|
||||
|
||||
@@ -162,17 +162,16 @@ func (ws *WSState) ReplaceShell(shell *wsshell.WSShell) {
|
||||
func (ws *WSState) handleConnection() error {
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancelFn()
|
||||
connectUpdate, err := sstore.GetConnectUpdate(ctx)
|
||||
update, err := sstore.GetAllSessions(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting sessions: %w", err)
|
||||
}
|
||||
remotes := remote.GetAllRemoteRuntimeState()
|
||||
connectUpdate.Remotes = remotes
|
||||
update.Remotes = remotes
|
||||
// restore status indicators
|
||||
connectUpdate.ScreenStatusIndicators, connectUpdate.ScreenNumRunningCommands = sstore.GetCurrentIndicatorState()
|
||||
mu := &sstore.ModelUpdate{}
|
||||
sstore.AddUpdate(mu, *connectUpdate)
|
||||
err = ws.Shell.WriteJson(mu)
|
||||
update.ScreenStatusIndicators, update.ScreenNumRunningCommands = sstore.GetCurrentIndicatorState()
|
||||
update.Connect = true
|
||||
err = ws.Shell.WriteJson(update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+58
-79
@@ -453,32 +453,20 @@ func GetBareSessionById(ctx context.Context, sessionId string) (*SessionType, er
|
||||
return &rtn, nil
|
||||
}
|
||||
|
||||
const getAllSessionsQuery = `SELECT * FROM session ORDER BY archived, sessionidx, archivedts`
|
||||
|
||||
// Gets all sessions, including archived
|
||||
func GetAllSessions(ctx context.Context) ([]*SessionType, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) ([]*SessionType, error) {
|
||||
rtn := []*SessionType{}
|
||||
tx.Select(&rtn, getAllSessionsQuery)
|
||||
return rtn, nil
|
||||
})
|
||||
}
|
||||
|
||||
// Get all sessions and screens, including remotes
|
||||
func GetConnectUpdate(ctx context.Context) (*ConnectUpdate, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ConnectUpdate, error) {
|
||||
update := &ConnectUpdate{}
|
||||
sessions := []*SessionType{}
|
||||
tx.Select(&sessions, getAllSessionsQuery)
|
||||
func GetAllSessions(ctx context.Context) (*ModelUpdate, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ModelUpdate, error) {
|
||||
update := &ModelUpdate{}
|
||||
query := `SELECT * FROM session ORDER BY archived, sessionidx, archivedts`
|
||||
tx.Select(&update.Sessions, query)
|
||||
sessionMap := make(map[string]*SessionType)
|
||||
for _, session := range sessions {
|
||||
for _, session := range update.Sessions {
|
||||
sessionMap[session.SessionId] = session
|
||||
update.Sessions = append(update.Sessions, session)
|
||||
session.Full = true
|
||||
}
|
||||
query := `SELECT * FROM screen ORDER BY archived, screenidx, archivedts`
|
||||
screens := dbutil.SelectMapsGen[*ScreenType](tx, query)
|
||||
for _, screen := range screens {
|
||||
update.Screens = append(update.Screens, screen)
|
||||
query = `SELECT * FROM screen ORDER BY archived, screenidx, archivedts`
|
||||
update.Screens = dbutil.SelectMapsGen[*ScreenType](tx, query)
|
||||
for _, screen := range update.Screens {
|
||||
screen.Full = true
|
||||
}
|
||||
query = `SELECT * FROM remote_instance`
|
||||
riArr := dbutil.SelectMapsGen[*RemoteInstance](tx, query)
|
||||
@@ -514,15 +502,19 @@ func GetSessionScreens(ctx context.Context, sessionId string) ([]*ScreenType, er
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) ([]*ScreenType, error) {
|
||||
query := `SELECT * FROM screen WHERE sessionid = ? ORDER BY archived, screenidx, archivedts`
|
||||
rtn := dbutil.SelectMapsGen[*ScreenType](tx, query, sessionId)
|
||||
for _, screen := range rtn {
|
||||
screen.Full = true
|
||||
}
|
||||
return rtn, nil
|
||||
})
|
||||
}
|
||||
|
||||
func GetSessionById(ctx context.Context, id string) (*SessionType, error) {
|
||||
allSessions, err := GetAllSessions(ctx)
|
||||
allSessionsUpdate, err := GetAllSessions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allSessions := allSessionsUpdate.Sessions
|
||||
for _, session := range allSessions {
|
||||
if session.SessionId == id {
|
||||
return session, nil
|
||||
@@ -577,11 +569,7 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
screenUpdateItems := GetUpdateItems[ScreenType](screenUpdate)
|
||||
if len(screenUpdateItems) < 1 {
|
||||
return fmt.Errorf("no screen update items")
|
||||
}
|
||||
newScreen = screenUpdateItems[0]
|
||||
newScreen = screenUpdate.Screens[0]
|
||||
if activate {
|
||||
query = `UPDATE client SET activesessionid = ?`
|
||||
tx.Exec(query, newSessionId)
|
||||
@@ -595,11 +583,12 @@ func InsertSessionWithName(ctx context.Context, sessionName string, activate boo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *session)
|
||||
AddUpdate(update, *newScreen)
|
||||
update := &ModelUpdate{
|
||||
Sessions: []*SessionType{session},
|
||||
Screens: []*ScreenType{newScreen},
|
||||
}
|
||||
if activate {
|
||||
AddUpdate(update, ActiveSessionIdUpdate(newSessionId))
|
||||
update.ActiveSessionId = newSessionId
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -753,15 +742,14 @@ func InsertScreen(ctx context.Context, sessionId string, origScreenName string,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *newScreen)
|
||||
update := &ModelUpdate{Screens: []*ScreenType{newScreen}}
|
||||
if activate {
|
||||
bareSession, err := GetBareSessionById(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
AddUpdate(update, *bareSession)
|
||||
UpdateWithCurrentOpenAICmdInfoChat(newScreenId, update)
|
||||
update.Sessions = []*SessionType{bareSession}
|
||||
update.OpenAICmdInfoChat = ScreenMemGetCmdInfoChat(newScreenId).Messages
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -770,6 +758,7 @@ func GetScreenById(ctx context.Context, screenId string) (*ScreenType, error) {
|
||||
return WithTxRtn(ctx, func(tx *TxWrap) (*ScreenType, error) {
|
||||
query := `SELECT * FROM screen WHERE screenid = ?`
|
||||
screen := dbutil.GetMapGen[*ScreenType](tx, query, screenId)
|
||||
screen.Full = true
|
||||
return screen, nil
|
||||
})
|
||||
}
|
||||
@@ -877,18 +866,17 @@ func GetCmdByScreenId(ctx context.Context, screenId string, lineId string) (*Cmd
|
||||
|
||||
func UpdateWithClearOpenAICmdInfo(screenId string) (*ModelUpdate, error) {
|
||||
ScreenMemClearCmdInfoChat(screenId)
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId, nil)
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId)
|
||||
}
|
||||
|
||||
func UpdateWithAddNewOpenAICmdInfoPacket(ctx context.Context, screenId string, pk *packet.OpenAICmdInfoChatMessage) (*ModelUpdate, error) {
|
||||
ScreenMemAddCmdInfoChatMessage(screenId, pk)
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId, nil)
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId)
|
||||
}
|
||||
|
||||
func UpdateWithCurrentOpenAICmdInfoChat(screenId string, update *ModelUpdate) (*ModelUpdate, error) {
|
||||
ret := &ModelUpdate{}
|
||||
AddOpenAICmdInfoChatUpdate(ret, ScreenMemGetCmdInfoChat(screenId).Messages)
|
||||
return ret, nil
|
||||
func UpdateWithCurrentOpenAICmdInfoChat(screenId string) (*ModelUpdate, error) {
|
||||
cmdInfoUpdate := ScreenMemGetCmdInfoChat(screenId).Messages
|
||||
return &ModelUpdate{OpenAICmdInfoChat: cmdInfoUpdate}, nil
|
||||
}
|
||||
|
||||
func UpdateWithUpdateOpenAICmdInfoPacket(ctx context.Context, screenId string, messageID int, pk *packet.OpenAICmdInfoChatMessage) (*ModelUpdate, error) {
|
||||
@@ -896,7 +884,7 @@ func UpdateWithUpdateOpenAICmdInfoPacket(ctx context.Context, screenId string, m
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId, nil)
|
||||
return UpdateWithCurrentOpenAICmdInfoChat(screenId)
|
||||
}
|
||||
|
||||
func UpdateCmdForRestart(ctx context.Context, ck base.CommandKey, ts int64, cmdPid int, remotePid int, termOpts *TermOpts) error {
|
||||
@@ -947,8 +935,7 @@ func UpdateCmdDoneInfo(ctx context.Context, ck base.CommandKey, donePk *packet.C
|
||||
return nil, fmt.Errorf("cmd data not found for ck[%s]", ck)
|
||||
}
|
||||
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *rtnCmd)
|
||||
update := &ModelUpdate{Cmd: rtnCmd}
|
||||
|
||||
// Update in-memory screen indicator status
|
||||
var indicator StatusIndicatorLevel
|
||||
@@ -1114,13 +1101,11 @@ func SwitchScreenById(ctx context.Context, sessionId string, screenId string) (*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(sessionId))
|
||||
AddUpdate(update, *bareSession)
|
||||
update := &ModelUpdate{ActiveSessionId: sessionId, Sessions: []*SessionType{bareSession}}
|
||||
memState := GetScreenMemState(screenId)
|
||||
if memState != nil {
|
||||
AddCmdLineUpdate(update, memState.CmdInputText)
|
||||
UpdateWithCurrentOpenAICmdInfoChat(screenId, update)
|
||||
update.CmdLine = &memState.CmdInputText
|
||||
update.OpenAICmdInfoChat = ScreenMemGetCmdInfoChat(screenId).Messages
|
||||
|
||||
// Clear any previous status indicator for this screen
|
||||
err := ResetStatusIndicator_Update(update, screenId)
|
||||
@@ -1188,14 +1173,13 @@ func ArchiveScreen(ctx context.Context, sessionId string, screenId string) (Upda
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot retrive archived screen: %w", err)
|
||||
}
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *newScreen)
|
||||
update := &ModelUpdate{Screens: []*ScreenType{newScreen}}
|
||||
if isActive {
|
||||
bareSession, err := GetBareSessionById(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
AddUpdate(update, *bareSession)
|
||||
update.Sessions = []*SessionType{bareSession}
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -1215,7 +1199,7 @@ func UnArchiveScreen(ctx context.Context, sessionId string, screenId string) err
|
||||
}
|
||||
|
||||
// if sessionDel is passed, we do *not* delete the screen directory (session delete will handle that)
|
||||
func DeleteScreen(ctx context.Context, screenId string, sessionDel bool, update *ModelUpdate) (*ModelUpdate, error) {
|
||||
func DeleteScreen(ctx context.Context, screenId string, sessionDel bool) (*ModelUpdate, error) {
|
||||
var sessionId string
|
||||
var isActive bool
|
||||
var screenTombstone *ScreenTombstoneType
|
||||
@@ -1275,17 +1259,14 @@ func DeleteScreen(ctx context.Context, screenId string, sessionDel bool, update
|
||||
if !sessionDel {
|
||||
GoDeleteScreenDirs(screenId)
|
||||
}
|
||||
if update == nil {
|
||||
update = &ModelUpdate{}
|
||||
}
|
||||
AddUpdate(update, *screenTombstone)
|
||||
AddUpdate(update, ScreenType{SessionId: sessionId, ScreenId: screenId, Remove: true})
|
||||
update := &ModelUpdate{ScreenTombstones: []*ScreenTombstoneType{screenTombstone}}
|
||||
update.Screens = []*ScreenType{{SessionId: sessionId, ScreenId: screenId, Remove: true}}
|
||||
if isActive {
|
||||
bareSession, err := GetBareSessionById(ctx, sessionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
AddUpdate(update, *bareSession)
|
||||
update.Sessions = []*SessionType{bareSession}
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -1535,9 +1516,7 @@ func ArchiveScreenLines(ctx context.Context, screenId string) (*ModelUpdate, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := &ModelUpdate{}
|
||||
AddUpdate(ret, *screenLines)
|
||||
return ret, nil
|
||||
return &ModelUpdate{ScreenLines: screenLines}, nil
|
||||
}
|
||||
|
||||
func DeleteScreenLines(ctx context.Context, screenId string) (*ModelUpdate, error) {
|
||||
@@ -1579,10 +1558,7 @@ func DeleteScreenLines(ctx context.Context, screenId string) (*ModelUpdate, erro
|
||||
}
|
||||
screenLines.Lines = append(screenLines.Lines, line)
|
||||
}
|
||||
ret := &ModelUpdate{}
|
||||
AddUpdate(ret, *screen)
|
||||
AddUpdate(ret, *screenLines)
|
||||
return ret, nil
|
||||
return &ModelUpdate{Screens: []*ScreenType{screen}, ScreenLines: screenLines}, nil
|
||||
}
|
||||
|
||||
func GetRunningScreenCmds(ctx context.Context, screenId string) ([]*CmdType, error) {
|
||||
@@ -1645,10 +1621,16 @@ func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error)
|
||||
query := `SELECT screenid FROM screen WHERE sessionid = ?`
|
||||
screenIds = tx.SelectStrings(query, sessionId)
|
||||
for _, screenId := range screenIds {
|
||||
_, err := DeleteScreen(tx.Context(), screenId, true, update)
|
||||
screenUpdate, err := DeleteScreen(tx.Context(), screenId, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting screen[%s]: %v", screenId, err)
|
||||
}
|
||||
if len(screenUpdate.Screens) > 0 {
|
||||
update.Screens = append(update.Screens, screenUpdate.Screens...)
|
||||
}
|
||||
if len(screenUpdate.ScreenTombstones) > 0 {
|
||||
update.ScreenTombstones = append(update.ScreenTombstones, screenUpdate.ScreenTombstones...)
|
||||
}
|
||||
}
|
||||
query = `DELETE FROM session WHERE sessionid = ?`
|
||||
tx.Exec(query, sessionId)
|
||||
@@ -1668,12 +1650,10 @@ func DeleteSession(ctx context.Context, sessionId string) (UpdatePacket, error)
|
||||
}
|
||||
GoDeleteScreenDirs(screenIds...)
|
||||
if newActiveSessionId != "" {
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(newActiveSessionId))
|
||||
}
|
||||
AddUpdate(update, SessionType{SessionId: sessionId, Remove: true})
|
||||
if sessionTombstone != nil {
|
||||
AddUpdate(update, *sessionTombstone)
|
||||
update.ActiveSessionId = newActiveSessionId
|
||||
}
|
||||
update.Sessions = append(update.Sessions, &SessionType{SessionId: sessionId, Remove: true})
|
||||
update.SessionTombstones = []*SessionTombstoneType{sessionTombstone}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
@@ -1725,10 +1705,10 @@ func ArchiveSession(ctx context.Context, sessionId string) (*ModelUpdate, error)
|
||||
bareSession, _ := GetBareSessionById(ctx, sessionId)
|
||||
update := &ModelUpdate{}
|
||||
if bareSession != nil {
|
||||
AddUpdate(update, *bareSession)
|
||||
update.Sessions = append(update.Sessions, bareSession)
|
||||
}
|
||||
if newActiveSessionId != "" {
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(newActiveSessionId))
|
||||
update.ActiveSessionId = newActiveSessionId
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
@@ -1760,12 +1740,11 @@ func UnArchiveSession(ctx context.Context, sessionId string, activate bool) (*Mo
|
||||
}
|
||||
bareSession, _ := GetBareSessionById(ctx, sessionId)
|
||||
update := &ModelUpdate{}
|
||||
|
||||
if bareSession != nil {
|
||||
AddUpdate(update, *bareSession)
|
||||
update.Sessions = append(update.Sessions, bareSession)
|
||||
}
|
||||
if activate {
|
||||
AddUpdate(update, (ActiveSessionIdUpdate)(sessionId))
|
||||
update.ActiveSessionId = sessionId
|
||||
}
|
||||
return update, nil
|
||||
}
|
||||
|
||||
@@ -336,10 +336,6 @@ func (cdata *ClientData) Clean() *ClientData {
|
||||
return &rtn
|
||||
}
|
||||
|
||||
func (ClientData) UpdateType() string {
|
||||
return "clientdata"
|
||||
}
|
||||
|
||||
type SessionType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
Name string `json:"name"`
|
||||
@@ -353,17 +349,7 @@ type SessionType struct {
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
}
|
||||
|
||||
func (SessionType) UpdateType() string {
|
||||
return "session"
|
||||
}
|
||||
|
||||
func MakeSessionUpdateForRemote(sessionId string, ri *RemoteInstance) SessionType {
|
||||
return SessionType{
|
||||
SessionId: sessionId,
|
||||
Remotes: []*RemoteInstance{ri},
|
||||
}
|
||||
Full bool `json:"full,omitempty"`
|
||||
}
|
||||
|
||||
type SessionTombstoneType struct {
|
||||
@@ -374,10 +360,6 @@ type SessionTombstoneType struct {
|
||||
|
||||
func (SessionTombstoneType) UseDBMap() {}
|
||||
|
||||
func (SessionTombstoneType) UpdateType() string {
|
||||
return "sessiontombstone"
|
||||
}
|
||||
|
||||
type SessionStatsType struct {
|
||||
SessionId string `json:"sessionid"`
|
||||
NumScreens int `json:"numscreens"`
|
||||
@@ -447,10 +429,6 @@ type ScreenLinesType struct {
|
||||
|
||||
func (ScreenLinesType) UseDBMap() {}
|
||||
|
||||
func (ScreenLinesType) UpdateType() string {
|
||||
return "screenlines"
|
||||
}
|
||||
|
||||
type ScreenWebShareOpts struct {
|
||||
ShareName string `json:"sharename"`
|
||||
ViewKey string `json:"viewkey"`
|
||||
@@ -498,7 +476,9 @@ type ScreenType struct {
|
||||
ArchivedTs int64 `json:"archivedts,omitempty"`
|
||||
|
||||
// only for updates
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
Full bool `json:"full,omitempty"`
|
||||
Remove bool `json:"remove,omitempty"`
|
||||
StatusIndicator string `json:"statusindicator,omitempty"`
|
||||
}
|
||||
|
||||
func (s *ScreenType) ToMap() map[string]interface{} {
|
||||
@@ -546,24 +526,6 @@ func (s *ScreenType) FromMap(m map[string]interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (ScreenType) UpdateType() string {
|
||||
return "screen"
|
||||
}
|
||||
|
||||
func AddScreenUpdate(update *ModelUpdate, newScreen *ScreenType) {
|
||||
if newScreen == nil {
|
||||
return
|
||||
}
|
||||
screenUpdates := GetUpdateItems[ScreenType](update)
|
||||
for _, screenUpdate := range screenUpdates {
|
||||
if screenUpdate.ScreenId == newScreen.ScreenId {
|
||||
screenUpdate = newScreen
|
||||
return
|
||||
}
|
||||
}
|
||||
AddUpdate(update, newScreen)
|
||||
}
|
||||
|
||||
type ScreenTombstoneType struct {
|
||||
ScreenId string `json:"screenid"`
|
||||
SessionId string `json:"sessionid"`
|
||||
@@ -574,10 +536,6 @@ type ScreenTombstoneType struct {
|
||||
|
||||
func (ScreenTombstoneType) UseDBMap() {}
|
||||
|
||||
func (ScreenTombstoneType) UpdateType() string {
|
||||
return "screentombstone"
|
||||
}
|
||||
|
||||
const (
|
||||
LayoutFull = "full"
|
||||
)
|
||||
@@ -1057,10 +1015,6 @@ func (state RemoteRuntimeState) ExpandHomeDir(pathStr string) (string, error) {
|
||||
return path.Join(homeDir, pathStr[2:]), nil
|
||||
}
|
||||
|
||||
func (RemoteRuntimeState) UpdateType() string {
|
||||
return "remote"
|
||||
}
|
||||
|
||||
type RemoteType struct {
|
||||
RemoteId string `json:"remoteid"`
|
||||
RemoteType string `json:"remotetype"`
|
||||
@@ -1125,10 +1079,6 @@ type CmdType struct {
|
||||
Restarted bool `json:"restarted,omitempty"` // not persisted to DB
|
||||
}
|
||||
|
||||
func (CmdType) UpdateType() string {
|
||||
return "cmd"
|
||||
}
|
||||
|
||||
func (r *RemoteType) ToMap() map[string]interface{} {
|
||||
rtn := make(map[string]interface{})
|
||||
rtn["remoteid"] = r.RemoteId
|
||||
@@ -1506,10 +1456,10 @@ func SetStatusIndicatorLevel_Update(ctx context.Context, update *ModelUpdate, sc
|
||||
}
|
||||
}
|
||||
|
||||
AddUpdate(update, ScreenStatusIndicatorType{
|
||||
update.ScreenStatusIndicators = []*ScreenStatusIndicatorType{{
|
||||
ScreenId: screenId,
|
||||
Status: newStatus,
|
||||
})
|
||||
}}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1539,11 +1489,10 @@ func ResetStatusIndicator(screenId string) error {
|
||||
func IncrementNumRunningCmds_Update(update *ModelUpdate, screenId string, delta int) {
|
||||
newNum := ScreenMemIncrementNumRunningCommands(screenId, delta)
|
||||
log.Printf("IncrementNumRunningCmds_Update: screenId=%s, newNum=%d\n", screenId, newNum)
|
||||
AddUpdate(update, ScreenNumRunningCommandsType{
|
||||
update.ScreenNumRunningCommands = []*ScreenNumRunningCommandsType{{
|
||||
ScreenId: screenId,
|
||||
Num: newNum,
|
||||
})
|
||||
|
||||
}}
|
||||
}
|
||||
|
||||
func IncrementNumRunningCmds(screenId string, delta int) {
|
||||
|
||||
+144
-47
@@ -5,13 +5,14 @@ package sstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scpacket"
|
||||
)
|
||||
|
||||
@@ -22,7 +23,6 @@ const ModelUpdateStr = "model"
|
||||
const UpdateChSize = 100
|
||||
|
||||
type UpdatePacket interface {
|
||||
// The key to use when marshalling to JSON and interpreting in the client
|
||||
UpdateType() string
|
||||
Clean()
|
||||
}
|
||||
@@ -42,61 +42,136 @@ func (*PtyDataUpdate) UpdateType() string {
|
||||
|
||||
func (pdu *PtyDataUpdate) Clean() {}
|
||||
|
||||
// A collection of independent model updates to be sent to the client. Will be evaluated in order on the client.
|
||||
type ModelUpdate []*ModelUpdateItem
|
||||
type ModelUpdate struct {
|
||||
Sessions []*SessionType `json:"sessions,omitempty"`
|
||||
ActiveSessionId string `json:"activesessionid,omitempty"`
|
||||
Screens []*ScreenType `json:"screens,omitempty"`
|
||||
ScreenLines *ScreenLinesType `json:"screenlines,omitempty"`
|
||||
Line *LineType `json:"line,omitempty"`
|
||||
Lines []*LineType `json:"lines,omitempty"`
|
||||
Cmd *CmdType `json:"cmd,omitempty"`
|
||||
CmdLine *utilfn.StrWithPos `json:"cmdline,omitempty"`
|
||||
Info *InfoMsgType `json:"info,omitempty"`
|
||||
ClearInfo bool `json:"clearinfo,omitempty"`
|
||||
Remotes []RemoteRuntimeState `json:"remotes,omitempty"`
|
||||
History *HistoryInfoType `json:"history,omitempty"`
|
||||
Interactive bool `json:"interactive"`
|
||||
Connect bool `json:"connect,omitempty"`
|
||||
MainView string `json:"mainview,omitempty"`
|
||||
Bookmarks []*BookmarkType `json:"bookmarks,omitempty"`
|
||||
SelectedBookmark string `json:"selectedbookmark,omitempty"`
|
||||
HistoryViewData *HistoryViewData `json:"historyviewdata,omitempty"`
|
||||
ClientData *ClientData `json:"clientdata,omitempty"`
|
||||
RemoteView *RemoteViewType `json:"remoteview,omitempty"`
|
||||
ScreenTombstones []*ScreenTombstoneType `json:"screentombstones,omitempty"`
|
||||
SessionTombstones []*SessionTombstoneType `json:"sessiontombstones,omitempty"`
|
||||
OpenAICmdInfoChat []*packet.OpenAICmdInfoChatMessage `json:"openaicmdinfochat,omitempty"`
|
||||
AlertMessage *AlertMessageType `json:"alertmessage,omitempty"`
|
||||
ScreenStatusIndicators []*ScreenStatusIndicatorType `json:"screenstatusindicators,omitempty"`
|
||||
ScreenNumRunningCommands []*ScreenNumRunningCommandsType `json:"screennumrunningcommands,omitempty"`
|
||||
UserInputRequest *UserInputRequestType `json:"userinputrequest,omitempty"`
|
||||
}
|
||||
|
||||
func (*ModelUpdate) UpdateType() string {
|
||||
return ModelUpdateStr
|
||||
}
|
||||
|
||||
func (mu *ModelUpdate) MarshalJSON() ([]byte, error) {
|
||||
rtn := make([]map[string]any, 0)
|
||||
for _, u := range *mu {
|
||||
m := make(map[string]any)
|
||||
m[(*u).UpdateType()] = u
|
||||
rtn = append(rtn, m)
|
||||
}
|
||||
return json.Marshal(rtn)
|
||||
}
|
||||
|
||||
// An interface for all model updates
|
||||
type ModelUpdateItem interface {
|
||||
// The key to use when marshalling to JSON and interpreting in the client
|
||||
UpdateType() string
|
||||
}
|
||||
|
||||
// Clean the ClientData in an update, if present
|
||||
func (update *ModelUpdate) Clean() {
|
||||
if update == nil {
|
||||
return
|
||||
}
|
||||
clientDataUpdates := GetUpdateItems[ClientData](update)
|
||||
if len(clientDataUpdates) > 0 {
|
||||
lastUpdate := clientDataUpdates[len(clientDataUpdates)-1]
|
||||
lastUpdate.Clean()
|
||||
update.ClientData = update.ClientData.Clean()
|
||||
}
|
||||
|
||||
func (update *ModelUpdate) UpdateScreen(newScreen *ScreenType) {
|
||||
if newScreen == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (update *ModelUpdate) append(item *ModelUpdateItem) {
|
||||
*update = append(*update, item)
|
||||
}
|
||||
|
||||
// Add a collection of model updates to the update
|
||||
func AddUpdate(update *ModelUpdate, item ...ModelUpdateItem) {
|
||||
for _, i := range item {
|
||||
update.append(&i)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the items in the update that are of type I
|
||||
func GetUpdateItems[I ModelUpdateItem](update *ModelUpdate) []*I {
|
||||
ret := make([]*I, 0)
|
||||
for _, item := range *update {
|
||||
if i, ok := (*item).(I); ok {
|
||||
ret = append(ret, &i)
|
||||
for idx, screen := range update.Screens {
|
||||
if screen.ScreenId == newScreen.ScreenId {
|
||||
update.Screens[idx] = newScreen
|
||||
return
|
||||
}
|
||||
}
|
||||
return ret
|
||||
update.Screens = append(update.Screens, newScreen)
|
||||
}
|
||||
|
||||
// only sets InfoError if InfoError is not already set
|
||||
func (update *ModelUpdate) AddInfoError(errStr string) {
|
||||
if update.Info == nil {
|
||||
update.Info = &InfoMsgType{}
|
||||
}
|
||||
if update.Info.InfoError == "" {
|
||||
update.Info.InfoError = errStr
|
||||
}
|
||||
}
|
||||
|
||||
type RemoteViewType struct {
|
||||
RemoteShowAll bool `json:"remoteshowall,omitempty"`
|
||||
PtyRemoteId string `json:"ptyremoteid,omitempty"`
|
||||
RemoteEdit *RemoteEditType `json:"remoteedit,omitempty"`
|
||||
}
|
||||
|
||||
func InfoMsgUpdate(infoMsgFmt string, args ...interface{}) *ModelUpdate {
|
||||
msg := fmt.Sprintf(infoMsgFmt, args...)
|
||||
return &ModelUpdate{
|
||||
Info: &InfoMsgType{InfoMsg: msg},
|
||||
}
|
||||
}
|
||||
|
||||
type HistoryViewData struct {
|
||||
Items []*HistoryItemType `json:"items"`
|
||||
Offset int `json:"offset"`
|
||||
RawOffset int `json:"rawoffset"`
|
||||
NextRawOffset int `json:"nextrawoffset"`
|
||||
HasMore bool `json:"hasmore"`
|
||||
Lines []*LineType `json:"lines"`
|
||||
Cmds []*CmdType `json:"cmds"`
|
||||
}
|
||||
|
||||
type RemoteEditType struct {
|
||||
RemoteEdit bool `json:"remoteedit"`
|
||||
RemoteId string `json:"remoteid,omitempty"`
|
||||
ErrorStr string `json:"errorstr,omitempty"`
|
||||
InfoStr string `json:"infostr,omitempty"`
|
||||
KeyStr string `json:"keystr,omitempty"`
|
||||
HasPassword bool `json:"haspassword,omitempty"`
|
||||
}
|
||||
|
||||
type AlertMessageType struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
Message string `json:"message"`
|
||||
Confirm bool `json:"confirm,omitempty"`
|
||||
Markdown bool `json:"markdown,omitempty"`
|
||||
}
|
||||
|
||||
type InfoMsgType struct {
|
||||
InfoTitle string `json:"infotitle"`
|
||||
InfoError string `json:"infoerror,omitempty"`
|
||||
InfoMsg string `json:"infomsg,omitempty"`
|
||||
InfoMsgHtml bool `json:"infomsghtml,omitempty"`
|
||||
WebShareLink bool `json:"websharelink,omitempty"`
|
||||
InfoComps []string `json:"infocomps,omitempty"`
|
||||
InfoCompsMore bool `json:"infocompssmore,omitempty"`
|
||||
InfoLines []string `json:"infolines,omitempty"`
|
||||
TimeoutMs int64 `json:"timeoutms,omitempty"`
|
||||
}
|
||||
|
||||
type HistoryInfoType struct {
|
||||
HistoryType string `json:"historytype"`
|
||||
SessionId string `json:"sessionid,omitempty"`
|
||||
ScreenId string `json:"screenid,omitempty"`
|
||||
Items []*HistoryItemType `json:"items"`
|
||||
Show bool `json:"show"`
|
||||
}
|
||||
|
||||
type UserInputRequestType struct {
|
||||
RequestId string `json:"requestid"`
|
||||
QueryText string `json:"querytext"`
|
||||
ResponseType string `json:"responsetype"`
|
||||
Title string `json:"title"`
|
||||
Markdown bool `json:"markdown"`
|
||||
TimeoutMs int `json:"timeoutms"`
|
||||
}
|
||||
|
||||
type UpdateChannel struct {
|
||||
@@ -192,6 +267,29 @@ func (bus *UpdateBus) SendScreenUpdate(screenId string, update UpdatePacket) {
|
||||
}
|
||||
}
|
||||
|
||||
func MakeSessionsUpdateForRemote(sessionId string, ri *RemoteInstance) []*SessionType {
|
||||
return []*SessionType{
|
||||
{
|
||||
SessionId: sessionId,
|
||||
Remotes: []*RemoteInstance{ri},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type BookmarksViewType struct {
|
||||
Bookmarks []*BookmarkType `json:"bookmarks"`
|
||||
}
|
||||
|
||||
type ScreenStatusIndicatorType struct {
|
||||
ScreenId string `json:"screenid"`
|
||||
Status StatusIndicatorLevel `json:"status"`
|
||||
}
|
||||
|
||||
type ScreenNumRunningCommandsType struct {
|
||||
ScreenId string `json:"screenid"`
|
||||
Num int `json:"num"`
|
||||
}
|
||||
|
||||
func (bus *UpdateBus) registerUserInputChannel() (string, chan *scpacket.UserInputResponsePacketType) {
|
||||
bus.Lock.Lock()
|
||||
defer bus.Lock.Unlock()
|
||||
@@ -225,8 +323,7 @@ func (bus *UpdateBus) GetUserInput(ctx context.Context, userInputRequest *UserIn
|
||||
userInputRequest.RequestId = id
|
||||
deadline, _ := ctx.Deadline()
|
||||
userInputRequest.TimeoutMs = int(time.Until(deadline).Milliseconds()) - 500
|
||||
update := &ModelUpdate{}
|
||||
AddUpdate(update, *userInputRequest)
|
||||
update := &ModelUpdate{UserInputRequest: userInputRequest}
|
||||
bus.SendUpdate(update)
|
||||
log.Printf("test: %+v", userInputRequest)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user