Compare commits

..

19 Commits

Author SHA1 Message Date
Sylvia Crowe ea253c33ae merge 'main' into use-ssh-library--add-user-input
I had to reimplement a few front end changes but nothing too major aside
from that.
2024-02-08 15:51:32 -08:00
Sylvia Crowe 53de138832 fix: add the userinput.tsx changes
These were missed in the previous commit. Adding them now.
2024-02-08 13:07:37 -08:00
Sylvia Crowe 75778963c5 merge 'main' into use-ssh-library--add-user-input
This merge is rather large, so it needs some explaining. Most of it was
a straightforward merge, but there were a few markdown edits i made that
had to manually be resolved.

There were also a few path changes to be made in the userinput.tsx file.
2024-02-08 13:06:56 -08:00
Sylvia Crowe 89906d21d4 feat: create naive ui for ssh key passphrases
This isn't quite as reactive as the other methods, but it does attempt
to use publickey without a passphrase, then attempt to use the password
as the passphrase, and finally prompting the user for a passphrase. The
problem with this approach is that if multiple keys are used and they
all have passphrases, they need to all be checked up front. In practice,
this will not happen often, but it is something to be aware of.
2024-02-08 02:53:37 -08:00
Sylvia Crowe 747a2b784a fix: set number of retries to two again
I was wrong in my previous analysis. The number given is the total
number of tries. This is confusing when keyboard authentication and
password authentication are both available which usually doesn't happen.
2024-02-07 17:03:08 -08:00
Sylvia Crowe 84e7605e36 refactor: change argument order in GetUserInput
This is a simple change to move the context to the first argument of
GetUserInput to match the convention used elsewhere in the code.
2024-02-07 17:01:35 -08:00
Sylvia Crowe 839e338dad fix: set number of retries to one in ssh
Number of retries means number of attempts after the fact, not number of
total attempts. It has been adjusted from 2 to 1 to reflect this.
2024-02-07 16:24:27 -08:00
Sylvia Crowe 771046637d fix: allow automatic and interactive auth together
Previously, it was impossible to use to separate methods of the same
type to try ssh authentication. This made it impossible to make an auto
attempt before a manual one. This change restricts that by combining
them into one method where the auto attempt is tried once first and
cannot be tried again. Following that, interactive authentication can be
tried separately.

It also lowers the time limit on kbd interactive authentication to 15
seconds due to limitations on the library we are using.
2024-02-07 16:00:39 -08:00
Sylvia Crowe 8dc3b3b0c1 feat: add interactive password authentication
This makes the ssh password authentication interactive with its own user
input modal. Unfortunately, this method does not allow trying a default
first. This will need to be expanded in the future to accomodate that.
2024-02-07 14:50:34 -08:00
Sylvia Crowe 0a8c8221fd feat: add user input for kbd-interactive auth
This adds a modal so the user can respond to prompts provided using the
keyboard interactive authentication method.
2024-02-06 21:34:33 -08:00
Sylvia Crowe 38c6e8f5f8 merge branch 'main' into use-ssh-library--add-user-input 2024-02-05 16:36:15 -08:00
Sylvia Crowe def90a0493 feat: allow writing to known_hosts first pass
As a follow-up to the previous change, we now allow the user to respond
to interactive queries in order to determine if an unknown known hosts
key can be added to a known_hosts file if it is missing. This needs to
be refined further, but it gets the basic functionality there.
2024-02-05 16:26:54 -08:00
Sylvia Crowe e2d10cd807 feat: create first pass known_hosts detection
Manually integrating with golang's ssh library means that the code must
authenticate known_hosts on its own. This is a first pass at creating a
system that parses the known hosts files and denys a connection if there
is a mismatch. This needs to be updated with a means to add keys to the
known-hosts file if the user requests it.
2024-02-02 11:50:02 -08:00
Sylvia Crowe 26240bea97 feat: complete user input modal
This rounds out the most immediate concerns for the new user input
modal. The frontend now includes a timer to show how much time is left
and will close itself once it reaches zero. Css
formatting has been cleaned up to be more reasonable.

There is still some test code present on the back end. This will be
removed once actuall examples of the new modal are in place.
2024-01-31 23:00:50 -08:00
Sylvia Crowe fa9a0bd228 merge branch 'main' into use-ssh-library--add-user-input 2024-01-31 14:46:43 -08:00
Sylvia Crowe fa2c684c0e fix: add props to user input request modal
There was a second place that the modals were created that I previously
missed. This fixes that second casel
2024-01-31 11:58:32 -08:00
Sylvia Crowe 750e8bc9f7 refactor: update user input backend/interface
This updates the user input backend to fix a few potential bugs. It also
refactors the user input request and response types to better handle
markdown and errors while making it more convenient to work with.

A couple frontend changes were made to keep everything compatible.
2024-01-31 03:43:22 -08:00
Sylvia Crowe f781e358e5 feat: create frontend for user input requests
This is part of a change to allow the backend to request user input from
the frontend. This adds a component specifically for handling this
logic. It is only a starting point, and does not work perfectly yet.
2024-01-30 22:50:40 -08:00
Sylvia Crowe 98f6b84d3e feat: create backend for user input requests
This is the first part of a change that allows the backend to request
user input from the frontend. Essentially, the backend will send a
request for the user to answer some query, and the frontend will send
that answer back. It is blocking, so it needs to be used within a
goroutine.

There is some placeholder code in the frontend that will be updated in
future commits. Similarly, there is some debug code in the backend
remote.go file.
2024-01-29 16:19:34 -08:00
22 changed files with 899 additions and 1130 deletions
+2 -2
View File
@@ -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>
+14 -21
View File
@@ -14,7 +14,6 @@ import { sprintf } from "sprintf-js";
import { v4 as uuidv4 } from "uuid";
import { checkKeyPressed, adaptFromElectronKeyEvent, setKeyUtilPlatform } from "../util/keyutil";
import { platform } from "os";
import * as T from "../types/types";
const WaveAppPathVarName = "WAVETERM_APP_PATH";
const WaveDevVarName = "WAVETERM_DEV";
@@ -38,25 +37,21 @@ ensureDir(waveHome);
// normalize darwin/x64 to darwin/amd64 for GOARCH compatibility
let unamePlatform = process.platform;
let unameArch: string = process.arch;
``;
if (unameArch == "x64") {
unameArch = "amd64";
}
let logger: winston.Logger;
let transports: winston.transport[] = [
new winston.transports.File({ filename: path.join(waveHome, "waveterm-app.log"), level: "info" }),
];
if (isDev) {
transports.push(new winston.transports.Console());
}
let loggerConfig: winston.LoggerOptions = {
let logger;
let loggerConfig = {
level: "info",
format: winston.format.combine(
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
winston.format.printf((info) => `${info.timestamp} ${info.message}`)
),
transports: transports,
transports: [new winston.transports.File({ filename: path.join(waveHome, "waveterm-app.log"), level: "info" })],
};
if (isDev) {
loggerConfig.transports.push(new winston.transports.Console());
}
logger = winston.createLogger(loggerConfig);
function log(...msg) {
try {
@@ -80,7 +75,7 @@ if (isDev) {
}
let app = electron.app;
app.setName(isDev ? "Wave (Dev)" : "Wave");
let waveSrvProc: child_process.ChildProcessWithoutNullStreams | null = null;
let waveSrvProc = null;
let waveSrvShouldRestart = false;
electron.dialog.showErrorBox = (title, content) => {
@@ -106,8 +101,8 @@ function checkPromptMigrate() {
// don't migrate if we're running dev version or if wave home directory already exists
return;
}
let homeDir: string = process.env.HOME as string;
let promptHome: string = path.join(homeDir, "prompt");
let homeDir = process.env.HOME;
let promptHome = path.join(homeDir, "prompt");
if (!fs.existsSync(promptHome) || !fs.existsSync(path.join(promptHome, "prompt.db"))) {
// make sure we have a valid prompt home directory (prompt.db must exist inside)
return;
@@ -175,7 +170,7 @@ function readAuthKey() {
return authKeyStr.trim();
}
let menuTemplate: (Electron.MenuItem | Electron.MenuItemConstructorOptions)[] = [
let menuTemplate = [
{
role: "appMenu",
submenu: [
@@ -255,7 +250,7 @@ function shFrameNavHandler(event: any, url: any) {
return;
}
function createMainWindow(clientData: T.ClientDataType | null) {
function createMainWindow(clientData) {
let bounds = calcBounds(clientData);
setKeyUtilPlatform(platform());
let win = new electron.BrowserWindow({
@@ -614,9 +609,7 @@ function runWaveSrv() {
pReject(new Error(sprintf("failed to start local server (%s)", waveSrvCmd)));
if (waveSrvShouldRestart) {
waveSrvShouldRestart = false;
// small timeout here so we can reuse the listen socket
// this is normally only used in dev mode for debugging
setTimeout(runWaveSrv, 500);
this.runWaveSrv();
}
});
proc.on("spawn", (e) => {
@@ -651,7 +644,7 @@ electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
}
console.log("context-editmenu");
let menu = new electron.Menu();
let menuItem: Electron.MenuItem;
let menuItem = null;
if (opts.showCut) {
menuItem = new electron.MenuItem({ label: "Cut", role: "cut" });
menu.append(menuItem);
@@ -664,7 +657,7 @@ electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
});
async function createMainWindowWrap() {
let clientData: T.ClientDataType | null = null;
let clientData = null;
try {
clientData = await getClientDataPoll(1);
} catch (e) {
+15 -10
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -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) => {
+1 -1
View File
@@ -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) {
+2 -2
View File
@@ -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 -45
View File
@@ -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;
@@ -560,14 +540,6 @@ type ReleaseInfoType = {
latestversion: string;
};
type ClientWinSizeType = {
width: number;
height: number;
top: number;
left: number;
fullscreen: boolean;
};
type ClientDataType = {
clientid: string;
userid: string;
@@ -577,7 +549,6 @@ type ClientDataType = {
dbversion: number;
openaiopts?: OpenAIOptsType;
releaseinfo?: ReleaseInfoType;
winsize: ClientWinSizeType;
};
type OpenAIOptsType = {
@@ -895,7 +866,6 @@ export type {
CmdInputTextPacketType,
OpenAICmdInfoChatMessageType,
ScreenStatusIndicatorUpdateType,
ScreenNumRunningCommandsUpdateType,
OV,
OArr,
OMap,
+69 -53
View File
@@ -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;
}
+4 -1
View File
@@ -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")
}
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -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
+11 -16
View File
@@ -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}})
}
}
+2 -3
View File
@@ -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")
}
+5 -6
View File
@@ -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
View File
@@ -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
}
+8 -59
View File
@@ -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) {

Some files were not shown because too many files have changed in this diff Show More