mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f03598bde1 | |||
| 97af45d4a0 | |||
| 818bcd5094 | |||
| d319e72609 | |||
| 7a5afccab3 | |||
| efe567398a | |||
| 187509504d | |||
| 903b26bfca | |||
| e692c7c180 | |||
| b37f7f722e | |||
| 53398ef499 |
@@ -8,6 +8,7 @@ export const SESSION_SETTINGS = "sessionSettings";
|
||||
export const LINE_SETTINGS = "lineSettings";
|
||||
export const CLIENT_SETTINGS = "clientSettings";
|
||||
export const TAB_SWITCHER = "tabSwitcher";
|
||||
export const USER_INPUT = "userInput";
|
||||
|
||||
export const LineContainer_Main = "main";
|
||||
export const LineContainer_History = "history";
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
margin-bottom: 10px;
|
||||
font-family: @markdown-font;
|
||||
font-size: 14px;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
code {
|
||||
background-color: @markdown-highlight;
|
||||
|
||||
@@ -60,7 +60,13 @@ class PasswordField extends TextField {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn(`wave-textfield wave-password ${className || ""}`, { focused: focused, error: error })}>
|
||||
<div
|
||||
className={cn(`wave-textfield wave-password ${className || ""}`, {
|
||||
focused: focused,
|
||||
error: error,
|
||||
"no-label": !label,
|
||||
})}
|
||||
>
|
||||
{decoration?.startDecoration && <>{decoration.startDecoration}</>}
|
||||
<div className="wave-textfield-inner">
|
||||
<label
|
||||
|
||||
@@ -9,3 +9,4 @@ export { TabSwitcherModal } from "./tabswitcher";
|
||||
export { SessionSettingsModal } from "./sessionsettings";
|
||||
export { ScreenSettingsModal } from "./screensettings";
|
||||
export { LineSettingsModal } from "./linesettings";
|
||||
export { UserInputModal } from "./userinput";
|
||||
|
||||
@@ -17,7 +17,7 @@ class ModalsProvider extends React.Component {
|
||||
for (let i = 0; i < store.length; i++) {
|
||||
let entry = store[i];
|
||||
let Comp = entry.component;
|
||||
rtn.push(<Comp key={entry.uniqueKey} />);
|
||||
rtn.push(<Comp key={entry.uniqueKey} {...entry.props} />);
|
||||
}
|
||||
return <>{rtn}</>;
|
||||
}
|
||||
|
||||
@@ -12,19 +12,21 @@ import {
|
||||
SessionSettingsModal,
|
||||
ScreenSettingsModal,
|
||||
LineSettingsModal,
|
||||
UserInputModal,
|
||||
} from "../modals";
|
||||
import * as constants from "../../appconst";
|
||||
|
||||
const modalsRegistry: { [key: string]: () => React.ReactElement } = {
|
||||
[constants.ABOUT]: () => <AboutModal />,
|
||||
[constants.CREATE_REMOTE]: () => <CreateRemoteConnModal />,
|
||||
[constants.VIEW_REMOTE]: () => <ViewRemoteConnDetailModal />,
|
||||
[constants.EDIT_REMOTE]: () => <EditRemoteConnModal />,
|
||||
[constants.ALERT]: () => <AlertModal />,
|
||||
[constants.SCREEN_SETTINGS]: () => <ScreenSettingsModal />,
|
||||
[constants.SESSION_SETTINGS]: () => <SessionSettingsModal />,
|
||||
[constants.LINE_SETTINGS]: () => <LineSettingsModal />,
|
||||
[constants.TAB_SWITCHER]: () => <TabSwitcherModal />,
|
||||
const modalsRegistry: { [key: string]: React.ComponentType } = {
|
||||
[constants.ABOUT]: AboutModal,
|
||||
[constants.CREATE_REMOTE]: CreateRemoteConnModal,
|
||||
[constants.VIEW_REMOTE]: ViewRemoteConnDetailModal,
|
||||
[constants.EDIT_REMOTE]: EditRemoteConnModal,
|
||||
[constants.ALERT]: AlertModal,
|
||||
[constants.SCREEN_SETTINGS]: ScreenSettingsModal,
|
||||
[constants.SESSION_SETTINGS]: SessionSettingsModal,
|
||||
[constants.LINE_SETTINGS]: LineSettingsModal,
|
||||
[constants.TAB_SWITCHER]: TabSwitcherModal,
|
||||
[constants.USER_INPUT]: UserInputModal,
|
||||
};
|
||||
|
||||
export { modalsRegistry };
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
@import "../../../app/common/themes/themes.less";
|
||||
|
||||
.userinput-modal {
|
||||
width: 500px;
|
||||
|
||||
.wave-modal-content {
|
||||
.wave-modal-body {
|
||||
padding: 20px 20px;
|
||||
|
||||
.userinput-query {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import * as React from "react";
|
||||
import { GlobalModel } from "../../../models";
|
||||
import { Choose, When, If } from "tsx-control-statements/components";
|
||||
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 [countdown, setCountdown] = React.useState(Math.floor(userInputRequest.timeoutms / 1000));
|
||||
|
||||
const closeModal = React.useCallback(() => {
|
||||
GlobalModel.sendUserInput({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
errormsg: "Canceled by the user",
|
||||
});
|
||||
GlobalModel.remotesModel.closeModal();
|
||||
}, [responseText, userInputRequest]);
|
||||
|
||||
const handleSendText = React.useCallback(() => {
|
||||
GlobalModel.sendUserInput({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
text: responseText,
|
||||
});
|
||||
GlobalModel.remotesModel.closeModal();
|
||||
}, [responseText, userInputRequest]);
|
||||
|
||||
const handleSendConfirm = React.useCallback(
|
||||
(response: boolean) => {
|
||||
GlobalModel.sendUserInput({
|
||||
type: "userinputresp",
|
||||
requestid: userInputRequest.requestid,
|
||||
confirm: response,
|
||||
});
|
||||
GlobalModel.remotesModel.closeModal();
|
||||
},
|
||||
[userInputRequest]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
if (countdown == 0) {
|
||||
timeout = setTimeout(() => {
|
||||
GlobalModel.remotesModel.closeModal();
|
||||
}, 300);
|
||||
} else {
|
||||
timeout = setTimeout(() => {
|
||||
setCountdown(countdown - 1);
|
||||
}, 1000);
|
||||
}
|
||||
return () => clearTimeout(timeout);
|
||||
}, [countdown]);
|
||||
|
||||
return (
|
||||
<Modal className="userinput-modal">
|
||||
<Modal.Header onClose={closeModal} title={userInputRequest.title + ` (${countdown})`} />
|
||||
<div className="wave-modal-body">
|
||||
<div className="userinput-query">
|
||||
<If condition={userInputRequest.markdown}>
|
||||
<Markdown text={userInputRequest.querytext} />
|
||||
</If>
|
||||
<If condition={!userInputRequest.markdown}>{userInputRequest.querytext}</If>
|
||||
</div>
|
||||
<Choose>
|
||||
<When condition={userInputRequest.responsetype == "text"}>
|
||||
<PasswordField onChange={setResponseText} value={responseText} maxLength={400} />
|
||||
</When>
|
||||
</Choose>
|
||||
</div>
|
||||
<Choose>
|
||||
<When condition={userInputRequest.responsetype == "text"}>
|
||||
<Modal.Footer onCancel={closeModal} onOk={handleSendText} okLabel="Continue" />
|
||||
</When>
|
||||
<When condition={userInputRequest.responsetype == "confirm"}>
|
||||
<Modal.Footer
|
||||
onCancel={() => handleSendConfirm(false)}
|
||||
onOk={() => handleSendConfirm(true)}
|
||||
okLabel="Yes"
|
||||
cancelLabel="No"
|
||||
/>
|
||||
</When>
|
||||
</Choose>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -54,6 +54,8 @@
|
||||
}
|
||||
|
||||
.remote-detail {
|
||||
width: 100%;
|
||||
|
||||
.settings-field {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -91,8 +93,9 @@
|
||||
}
|
||||
|
||||
.terminal-wrapper {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
.terminal-connectelem {
|
||||
height: 163px !important; // Needed to override plugin height
|
||||
@@ -111,7 +114,6 @@
|
||||
|
||||
.xterm-screen {
|
||||
padding: 10px;
|
||||
width: 541px !important; // Needed to override plugin width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,10 @@ 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();
|
||||
@@ -293,7 +291,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(RemotePtyCols, termFontSize);
|
||||
let termWidth = textmeasure.termWidthFromCols(appconst.RemotePtyCols, termFontSize);
|
||||
let remoteAliasText = util.isBlank(remote.remotealias) ? "(none)" : remote.remotealias;
|
||||
let selectedRemoteStatus = this.getSelectedRemote().status;
|
||||
|
||||
@@ -371,7 +369,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
ref={this.termRef}
|
||||
data-remoteid={remote.remoteid}
|
||||
style={{
|
||||
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize),
|
||||
height: textmeasure.termHeightFromRows(appconst.RemotePtyRows, termFontSize),
|
||||
width: termWidth,
|
||||
}}
|
||||
></div>
|
||||
|
||||
+10
-15
@@ -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,7 +207,6 @@ class InputModel {
|
||||
this.historyQueryOpts.set(opts);
|
||||
let bestIndex = this.findBestNewIndex(oldItem);
|
||||
setTimeout(() => this.setHistoryIndex(bestIndex, true), 10);
|
||||
return;
|
||||
})();
|
||||
}
|
||||
|
||||
@@ -624,13 +623,17 @@ class InputModel {
|
||||
}
|
||||
|
||||
openAIAssistantChat(): void {
|
||||
this.aIChatShow.set(true);
|
||||
this.setAIChatFocus();
|
||||
mobx.action(() => {
|
||||
this.aIChatShow.set(true);
|
||||
this.setAIChatFocus();
|
||||
})();
|
||||
}
|
||||
|
||||
closeAIAssistantChat(): void {
|
||||
this.aIChatShow.set(false);
|
||||
this.giveFocus();
|
||||
mobx.action(() => {
|
||||
this.aIChatShow.set(false);
|
||||
this.giveFocus();
|
||||
})();
|
||||
}
|
||||
|
||||
clearAIAssistantChat(): void {
|
||||
@@ -721,14 +724,6 @@ 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;
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ import { modalsRegistry } from "../app/common/modals/registry";
|
||||
import { OArr } from "../types/types";
|
||||
|
||||
class ModalsModel {
|
||||
store: OArr<ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store" });
|
||||
store: OArr<ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store", deep: false });
|
||||
|
||||
pushModal(modalId: string) {
|
||||
pushModal(modalId: string, props?: any) {
|
||||
const modalFactory = modalsRegistry[modalId];
|
||||
|
||||
if (modalFactory && !this.store.some((modal) => modal.id === modalId)) {
|
||||
mobx.action(() => {
|
||||
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4() });
|
||||
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4(), props });
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
+299
-242
File diff suppressed because it is too large
Load Diff
@@ -51,6 +51,8 @@ import {
|
||||
HistoryViewDataType,
|
||||
AlertMessageType,
|
||||
HistorySearchParams,
|
||||
UserInputRequest,
|
||||
UserInputResponsePacket,
|
||||
FocusTypeStrs,
|
||||
ScreenLinesType,
|
||||
HistoryTypeStrs,
|
||||
@@ -3376,14 +3378,14 @@ class RemotesModel {
|
||||
}
|
||||
|
||||
class ModalsModel {
|
||||
store: OArr<T.ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store" });
|
||||
store: OArr<T.ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store", deep: false });
|
||||
|
||||
pushModal(modalId: string) {
|
||||
pushModal(modalId: string, props?: any) {
|
||||
const modalFactory = modalsRegistry[modalId];
|
||||
|
||||
if (modalFactory && !this.store.some((modal) => modal.id === modalId)) {
|
||||
mobx.action(() => {
|
||||
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4() });
|
||||
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4(), props: props });
|
||||
})();
|
||||
}
|
||||
}
|
||||
@@ -4184,6 +4186,10 @@ class Model {
|
||||
this.getScreenById_single(snc.screenid)?.setNumRunningCmds(snc.num);
|
||||
}
|
||||
}
|
||||
if ("userinputrequest" in update) {
|
||||
let userInputRequest: UserInputRequest = update.userinputrequest;
|
||||
this.modalsModel.pushModal(appconst.USER_INPUT, userInputRequest);
|
||||
}
|
||||
}
|
||||
|
||||
updateRemotes(remotes: RemoteType[]): void {
|
||||
@@ -4591,6 +4597,10 @@ class Model {
|
||||
this.ws.pushMessage(inputPacket);
|
||||
}
|
||||
|
||||
sendUserInput(userInputResponsePacket: UserInputResponsePacket) {
|
||||
this.ws.pushMessage(userInputResponsePacket);
|
||||
}
|
||||
|
||||
sendCmdInputText(screenId: string, sp: T.StrWithPos) {
|
||||
let pk: T.CmdInputTextPacketType = {
|
||||
type: "cmdinputtext",
|
||||
@@ -12,9 +12,6 @@ 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, {
|
||||
@@ -180,14 +177,14 @@ class RemotesModel {
|
||||
return;
|
||||
}
|
||||
let termOpts = {
|
||||
rows: RemotePtyRows,
|
||||
cols: RemotePtyCols,
|
||||
rows: appconst.RemotePtyRows,
|
||||
cols: appconst.RemotePtyCols,
|
||||
flexrows: false,
|
||||
maxptysize: 64 * 1024,
|
||||
};
|
||||
let termWrap = new TermWrap(elem, {
|
||||
termContext: { remoteId: remoteId },
|
||||
usedRows: RemotePtyRows,
|
||||
usedRows: appconst.RemotePtyRows,
|
||||
termOpts: termOpts,
|
||||
winSize: null,
|
||||
keyHandler: (e, termWrap) => {
|
||||
|
||||
@@ -139,7 +139,7 @@ class ScreenLines {
|
||||
return;
|
||||
}
|
||||
let lineIdx = 0;
|
||||
for (lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
||||
for (lineIdx; 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-y: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
&:hover .xterm-viewport,
|
||||
&:focus-within .xterm-viewport {
|
||||
overflow-y: auto;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
+57
-15
@@ -29,7 +29,6 @@ type SessionDataType = {
|
||||
|
||||
// for updates
|
||||
remove?: boolean;
|
||||
full?: boolean;
|
||||
};
|
||||
|
||||
type LineStateType = { [k: string]: any };
|
||||
@@ -92,7 +91,6 @@ type ScreenDataType = {
|
||||
anchor: { anchorline: number; anchoroffset: number };
|
||||
|
||||
// for updates
|
||||
full?: boolean;
|
||||
remove?: boolean;
|
||||
};
|
||||
|
||||
@@ -260,6 +258,11 @@ type CmdDataType = {
|
||||
restarted?: boolean;
|
||||
};
|
||||
|
||||
type LineUpdateType = {
|
||||
line: LineType;
|
||||
cmd: CmdDataType;
|
||||
};
|
||||
|
||||
type PtyDataUpdateType = {
|
||||
screenid: string;
|
||||
lineid: string;
|
||||
@@ -309,30 +312,48 @@ 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;
|
||||
sessions?: SessionDataType[];
|
||||
session?: SessionDataType;
|
||||
activesessionid?: string;
|
||||
screens?: ScreenDataType[];
|
||||
screen?: ScreenDataType;
|
||||
screenlines?: ScreenLinesType;
|
||||
line?: LineType;
|
||||
lines?: LineType[];
|
||||
line?: LineUpdateType;
|
||||
cmd?: CmdDataType;
|
||||
info?: InfoType;
|
||||
cmdline?: StrWithPos;
|
||||
remotes?: RemoteType[];
|
||||
remote?: RemoteType;
|
||||
history?: HistoryInfoType;
|
||||
connect?: boolean;
|
||||
mainview?: string;
|
||||
bookmarks?: BookmarkType[];
|
||||
selectedbookmark?: string;
|
||||
connect?: ConnectUpdateType;
|
||||
mainview?: MainViewUpdateType;
|
||||
bookmarks?: BookmarksUpdateType;
|
||||
clientdata?: ClientDataType;
|
||||
historyviewdata?: HistoryViewDataType;
|
||||
remoteview?: RemoteViewType;
|
||||
openaicmdinfochat?: OpenAICmdInfoChatMessageType[];
|
||||
alertmessage?: AlertMessageType;
|
||||
screenstatusindicators?: ScreenStatusIndicatorUpdateType[];
|
||||
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType[];
|
||||
screenstatusindicator?: ScreenStatusIndicatorUpdateType;
|
||||
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType;
|
||||
userinputrequest?: UserInputRequest;
|
||||
};
|
||||
|
||||
type HistoryViewDataType = {
|
||||
@@ -414,7 +435,7 @@ type ContextMenuOpts = {
|
||||
showCut?: boolean;
|
||||
};
|
||||
|
||||
type UpdateMessage = PtyDataUpdateType | ModelUpdateType;
|
||||
type UpdateMessage = PtyDataUpdateType | ModelUpdateType[];
|
||||
|
||||
type RendererContext = {
|
||||
screenId: string;
|
||||
@@ -595,6 +616,23 @@ type HistorySearchParams = {
|
||||
filterCmds?: boolean;
|
||||
};
|
||||
|
||||
type UserInputRequest = {
|
||||
requestid: string;
|
||||
querytext: string;
|
||||
responsetype: string;
|
||||
title: string;
|
||||
markdown: boolean;
|
||||
timeoutms: number;
|
||||
};
|
||||
|
||||
type UserInputResponsePacket = {
|
||||
type: string;
|
||||
requestid: string;
|
||||
text?: string;
|
||||
confirm?: boolean;
|
||||
errormsg?: string;
|
||||
};
|
||||
|
||||
type RenderModeType = "normal" | "collapsed" | "expanded";
|
||||
|
||||
type WebScreen = {
|
||||
@@ -730,6 +768,7 @@ type ModalStoreEntry = {
|
||||
id: string;
|
||||
component: React.ComponentType;
|
||||
uniqueKey: string;
|
||||
props?: any;
|
||||
};
|
||||
|
||||
type StrWithPos = {
|
||||
@@ -809,6 +848,8 @@ export type {
|
||||
RenderModeType,
|
||||
AlertMessageType,
|
||||
HistorySearchParams,
|
||||
UserInputRequest,
|
||||
UserInputResponsePacket,
|
||||
ScreenLinesType,
|
||||
FocusTypeStrs,
|
||||
HistoryTypeStrs,
|
||||
@@ -845,6 +886,7 @@ export type {
|
||||
CmdInputTextPacketType,
|
||||
OpenAICmdInfoChatMessageType,
|
||||
ScreenStatusIndicatorUpdateType,
|
||||
ScreenNumRunningCommandsUpdateType,
|
||||
OV,
|
||||
OArr,
|
||||
OMap,
|
||||
|
||||
+53
-69
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023, Command Line Inc.
|
||||
// Copyright 2024, 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> {
|
||||
let errMsg = sprintf(
|
||||
const 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> {
|
||||
let contentType = resp.headers.get("Content-Type");
|
||||
if (contentType != null && contentType.startsWith("application/json")) {
|
||||
const contentType = resp.headers.get("Content-Type");
|
||||
if (contentType?.startsWith("application/json")) {
|
||||
return resp.text().then((textData) => {
|
||||
let rtnData: any = null;
|
||||
try {
|
||||
rtnData = JSON.parse(textData);
|
||||
} catch (err) {
|
||||
let errMsg = sprintf("Unparseable JSON: " + err.message);
|
||||
let rtnErr = new Error(errMsg);
|
||||
const errMsg = sprintf("Unparseable JSON: " + err.message);
|
||||
const rtnErr = new Error(errMsg);
|
||||
throw rtnErr;
|
||||
}
|
||||
if (rtnData != null && rtnData.error) {
|
||||
if (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);
|
||||
}
|
||||
let rtnData = fetchJsonData(resp, true);
|
||||
const rtnData = fetchJsonData(resp, true);
|
||||
return rtnData;
|
||||
}
|
||||
|
||||
function base64ToString(b64: string): string {
|
||||
let stringBytes = base64.toByteArray(b64);
|
||||
const stringBytes = base64.toByteArray(b64);
|
||||
return new TextDecoder().decode(stringBytes);
|
||||
}
|
||||
|
||||
function stringToBase64(input: string): string {
|
||||
let stringBytes = new TextEncoder().encode(input);
|
||||
const stringBytes = new TextEncoder().encode(input);
|
||||
return base64.fromByteArray(stringBytes);
|
||||
}
|
||||
|
||||
function base64ToArray(b64: string): Uint8Array {
|
||||
let rawStr = atob(b64);
|
||||
let rtnArr = new Uint8Array(new ArrayBuffer(rawStr.length));
|
||||
const rawStr = atob(b64);
|
||||
const rtnArr = new Uint8Array(new ArrayBuffer(rawStr.length));
|
||||
for (let i = 0; i < rawStr.length; i++) {
|
||||
rtnArr[i] = rawStr.charCodeAt(i);
|
||||
}
|
||||
@@ -92,7 +92,6 @@ function base64ToArray(b64: string): Uint8Array {
|
||||
|
||||
interface IDataType {
|
||||
remove?: boolean;
|
||||
full?: boolean;
|
||||
}
|
||||
|
||||
interface IObjType<DataType> {
|
||||
@@ -113,31 +112,28 @@ function genMergeSimpleData<T extends ISimpleDataType>(
|
||||
if (dataArr == null || dataArr.length == 0) {
|
||||
return;
|
||||
}
|
||||
let objMap: Record<string, T> = {};
|
||||
for (let i = 0; i < objs.length; i++) {
|
||||
let obj = objs[i];
|
||||
let id = idFn(obj);
|
||||
const objMap: Record<string, T> = {};
|
||||
for (const obj of objs) {
|
||||
const id = idFn(obj);
|
||||
objMap[id] = obj;
|
||||
}
|
||||
for (let i = 0; i < dataArr.length; i++) {
|
||||
let dataItem = dataArr[i];
|
||||
for (const dataItem of dataArr) {
|
||||
if (dataItem == null) {
|
||||
console.log("genMergeSimpleData, null item");
|
||||
console.trace();
|
||||
}
|
||||
let id = idFn(dataItem);
|
||||
const id = idFn(dataItem);
|
||||
if (dataItem.remove) {
|
||||
delete objMap[id];
|
||||
continue;
|
||||
} else {
|
||||
objMap[id] = dataItem;
|
||||
}
|
||||
}
|
||||
let newObjs = Object.values(objMap);
|
||||
const newObjs = Object.values(objMap);
|
||||
if (sortIdxFn) {
|
||||
newObjs.sort((a, b) => {
|
||||
let astr = sortIdxFn(a);
|
||||
let bstr = sortIdxFn(b);
|
||||
const astr = sortIdxFn(a);
|
||||
const bstr = sortIdxFn(b);
|
||||
return astr.localeCompare(bstr);
|
||||
});
|
||||
}
|
||||
@@ -155,20 +151,18 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
|
||||
if (dataArr == null || dataArr.length == 0) {
|
||||
return;
|
||||
}
|
||||
let objMap: Record<string, ObjType> = {};
|
||||
for (let i = 0; i < objs.length; i++) {
|
||||
let obj = objs[i];
|
||||
let id = objIdFn(obj);
|
||||
const objMap: Record<string, ObjType> = {};
|
||||
for (const obj of objs) {
|
||||
const id = objIdFn(obj);
|
||||
objMap[id] = obj;
|
||||
}
|
||||
for (let i = 0; i < dataArr.length; i++) {
|
||||
let dataItem = dataArr[i];
|
||||
for (const dataItem of dataArr) {
|
||||
if (dataItem == null) {
|
||||
console.log("genMergeData, null item");
|
||||
console.trace();
|
||||
continue;
|
||||
}
|
||||
let id = dataIdFn(dataItem);
|
||||
const id = dataIdFn(dataItem);
|
||||
let obj = objMap[id];
|
||||
if (dataItem.remove) {
|
||||
if (obj != null) {
|
||||
@@ -178,17 +172,13 @@ 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);
|
||||
}
|
||||
let newObjs = Object.values(objMap);
|
||||
const newObjs = Object.values(objMap);
|
||||
if (sortIdxFn) {
|
||||
newObjs.sort((a, b) => {
|
||||
return sortIdxFn(a) - sortIdxFn(b);
|
||||
@@ -204,18 +194,17 @@ function genMergeDataMap<ObjType extends IObjType<DataType>, DataType extends ID
|
||||
dataIdFn: (data: DataType) => string,
|
||||
ctorFn: (data: DataType) => ObjType
|
||||
): { added: string[]; removed: string[] } {
|
||||
let rtn: { added: string[]; removed: string[] } = { added: [], removed: [] };
|
||||
const rtn: { added: string[]; removed: string[] } = { added: [], removed: [] };
|
||||
if (dataArr == null || dataArr.length == 0) {
|
||||
return rtn;
|
||||
}
|
||||
for (let i = 0; i < dataArr.length; i++) {
|
||||
let dataItem = dataArr[i];
|
||||
for (const dataItem of dataArr) {
|
||||
if (dataItem == null) {
|
||||
console.log("genMergeDataMap, null item");
|
||||
console.trace();
|
||||
continue;
|
||||
}
|
||||
let id = dataIdFn(dataItem);
|
||||
const id = dataIdFn(dataItem);
|
||||
let obj = objMap.get(id);
|
||||
if (dataItem.remove) {
|
||||
if (obj != null) {
|
||||
@@ -226,10 +215,6 @@ 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);
|
||||
@@ -262,23 +247,23 @@ function incObs(inum: mobx.IObservableValue<number>) {
|
||||
|
||||
// @check:font
|
||||
function loadFonts() {
|
||||
let jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
||||
const jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
||||
style: "normal",
|
||||
weight: "400",
|
||||
});
|
||||
let jbmFont200 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-200.woff2')", {
|
||||
const jbmFont200 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-200.woff2')", {
|
||||
style: "normal",
|
||||
weight: "200",
|
||||
});
|
||||
let jbmFont700 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-700.woff2')", {
|
||||
const jbmFont700 = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-700.woff2')", {
|
||||
style: "normal",
|
||||
weight: "700",
|
||||
});
|
||||
let faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
||||
const faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
||||
style: "normal",
|
||||
weight: "normal",
|
||||
});
|
||||
let docFonts: any = document.fonts; // work around ts typing issue
|
||||
const docFonts: any = document.fonts; // work around ts typing issue
|
||||
docFonts.add(jbmFontNormal);
|
||||
docFonts.add(jbmFont200);
|
||||
docFonts.add(jbmFont700);
|
||||
@@ -296,13 +281,13 @@ function getTodayStr(): string {
|
||||
}
|
||||
|
||||
function getYesterdayStr(): string {
|
||||
let d = new Date();
|
||||
const d = new Date();
|
||||
d.setDate(d.getDate() - 1);
|
||||
return getDateStr(d);
|
||||
}
|
||||
|
||||
function getDateStr(d: Date): string {
|
||||
let yearStr = String(d.getFullYear());
|
||||
const yearStr = String(d.getFullYear());
|
||||
let monthStr = String(d.getMonth() + 1);
|
||||
if (monthStr.length == 1) {
|
||||
monthStr = "0" + monthStr;
|
||||
@@ -311,31 +296,30 @@ function getDateStr(d: Date): string {
|
||||
if (dayStr.length == 1) {
|
||||
dayStr = "0" + dayStr;
|
||||
}
|
||||
let dowStr = DOW_STRS[d.getDay()];
|
||||
const dowStr = DOW_STRS[d.getDay()];
|
||||
return dowStr + " " + yearStr + "-" + monthStr + "-" + dayStr;
|
||||
}
|
||||
|
||||
function getRemoteConnVal(r: RemoteType): number {
|
||||
if (r.status == "connected") {
|
||||
return 1;
|
||||
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 == "connecting") {
|
||||
return 2;
|
||||
}
|
||||
if (r.status == "disconnected") {
|
||||
return 3;
|
||||
}
|
||||
if (r.status == "error") {
|
||||
return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
function sortAndFilterRemotes(origRemotes: RemoteType[]): RemoteType[] {
|
||||
let remotes = origRemotes.filter((r) => !r.archived);
|
||||
const remotes = origRemotes.filter((r) => !r.archived);
|
||||
remotes.sort((a, b) => {
|
||||
let connValA = getRemoteConnVal(a);
|
||||
let connValB = getRemoteConnVal(b);
|
||||
const connValA = getRemoteConnVal(a);
|
||||
const connValB = getRemoteConnVal(b);
|
||||
if (connValA != connValB) {
|
||||
return connValA - connValB;
|
||||
}
|
||||
@@ -372,7 +356,7 @@ function openLink(url: string): void {
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
function getColorRGB(colorInput) {
|
||||
function getColorRGB(colorInput: string) {
|
||||
const tempElement = document.createElement("div");
|
||||
tempElement.style.color = colorInput;
|
||||
document.body.appendChild(tempElement);
|
||||
@@ -399,7 +383,7 @@ function getRemoteName(remote: RemoteType): string {
|
||||
if (remote == null) {
|
||||
return "";
|
||||
}
|
||||
let { remotealias, remotecanonicalname } = remote;
|
||||
const { remotealias, remotecanonicalname } = remote;
|
||||
return remotealias ? `${remotealias} [${remotecanonicalname}]` : remotecanonicalname;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,16 +156,12 @@ func (p *PacketParser) trySendRpcResponse(pk PacketType) bool {
|
||||
return false
|
||||
}
|
||||
p.Lock.Lock()
|
||||
defer p.Lock.Unlock()
|
||||
entry := p.RpcMap[respId]
|
||||
p.Lock.Unlock()
|
||||
if entry == nil {
|
||||
return false
|
||||
}
|
||||
// nonblocking send
|
||||
select {
|
||||
case entry.RespCh <- respPk:
|
||||
default:
|
||||
}
|
||||
entry.RespCh <- respPk
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user