mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d0b7bd770 | |||
| a9b9ff3362 | |||
| d2829c466d | |||
| f65e632c35 | |||
| acb3bd303b | |||
| 3ad7feedad | |||
| 24690ff931 | |||
| f510e1c904 | |||
| 35fa59aadd | |||
| d414657252 | |||
| b59dd6960f | |||
| 1ae74b767d | |||
| 7fa862b402 | |||
| 970c5c30fd | |||
| 2bcc8756e7 | |||
| 5ad26b10cd | |||
| ef7acda1bb | |||
| 29cd754358 | |||
| 648d98f065 | |||
| 5770e482a1 | |||
| 23b3250f18 | |||
| b62977470b | |||
| 07f2794b1b | |||
| cf27a8baff | |||
| aace48d42a | |||
| 15d02f3357 | |||
| 39d371681c | |||
| 412c3ac5a2 | |||
| 36484621ec | |||
| 72231ead1d | |||
| 81c1fd43f7 | |||
| c9a73c2204 | |||
| 434f980b49 | |||
| 75d462764d | |||
| c58c88af4e | |||
| 05be301ea2 | |||
| 27e5a9154d | |||
| a7d2148bc0 | |||
| ead75880e1 | |||
| 0bdb50cf91 | |||
| abf3448f07 | |||
| 8988d26867 | |||
| a084ca4801 | |||
| 36e2578a03 | |||
| a49487c035 | |||
| 03296043fb | |||
| ec797f55ff | |||
| 550461167b | |||
| cf5d2ecddf | |||
| c4128cd266 | |||
| 17bb07a47d |
@@ -8,7 +8,6 @@ export const SESSION_SETTINGS = "sessionSettings";
|
|||||||
export const LINE_SETTINGS = "lineSettings";
|
export const LINE_SETTINGS = "lineSettings";
|
||||||
export const CLIENT_SETTINGS = "clientSettings";
|
export const CLIENT_SETTINGS = "clientSettings";
|
||||||
export const TAB_SWITCHER = "tabSwitcher";
|
export const TAB_SWITCHER = "tabSwitcher";
|
||||||
export const USER_INPUT = "userInput";
|
|
||||||
|
|
||||||
export const LineContainer_Main = "main";
|
export const LineContainer_Main = "main";
|
||||||
export const LineContainer_History = "history";
|
export const LineContainer_History = "history";
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
font-family: @markdown-font;
|
font-family: @markdown-font;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
overflow-wrap: break-word;
|
|
||||||
|
|
||||||
code {
|
code {
|
||||||
background-color: @markdown-highlight;
|
background-color: @markdown-highlight;
|
||||||
|
|||||||
@@ -60,13 +60,7 @@ class PasswordField extends TextField {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={cn(`wave-textfield wave-password ${className || ""}`, { focused: focused, error: error })}>
|
||||||
className={cn(`wave-textfield wave-password ${className || ""}`, {
|
|
||||||
focused: focused,
|
|
||||||
error: error,
|
|
||||||
"no-label": !label,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{decoration?.startDecoration && <>{decoration.startDecoration}</>}
|
{decoration?.startDecoration && <>{decoration.startDecoration}</>}
|
||||||
<div className="wave-textfield-inner">
|
<div className="wave-textfield-inner">
|
||||||
<label
|
<label
|
||||||
|
|||||||
@@ -9,4 +9,3 @@ export { TabSwitcherModal } from "./tabswitcher";
|
|||||||
export { SessionSettingsModal } from "./sessionsettings";
|
export { SessionSettingsModal } from "./sessionsettings";
|
||||||
export { ScreenSettingsModal } from "./screensettings";
|
export { ScreenSettingsModal } from "./screensettings";
|
||||||
export { LineSettingsModal } from "./linesettings";
|
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++) {
|
for (let i = 0; i < store.length; i++) {
|
||||||
let entry = store[i];
|
let entry = store[i];
|
||||||
let Comp = entry.component;
|
let Comp = entry.component;
|
||||||
rtn.push(<Comp key={entry.uniqueKey} {...entry.props} />);
|
rtn.push(<Comp key={entry.uniqueKey} />);
|
||||||
}
|
}
|
||||||
return <>{rtn}</>;
|
return <>{rtn}</>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,21 +12,19 @@ import {
|
|||||||
SessionSettingsModal,
|
SessionSettingsModal,
|
||||||
ScreenSettingsModal,
|
ScreenSettingsModal,
|
||||||
LineSettingsModal,
|
LineSettingsModal,
|
||||||
UserInputModal,
|
|
||||||
} from "../modals";
|
} from "../modals";
|
||||||
import * as constants from "../../appconst";
|
import * as constants from "../../appconst";
|
||||||
|
|
||||||
const modalsRegistry: { [key: string]: React.ComponentType } = {
|
const modalsRegistry: { [key: string]: () => React.ReactElement } = {
|
||||||
[constants.ABOUT]: AboutModal,
|
[constants.ABOUT]: () => <AboutModal />,
|
||||||
[constants.CREATE_REMOTE]: CreateRemoteConnModal,
|
[constants.CREATE_REMOTE]: () => <CreateRemoteConnModal />,
|
||||||
[constants.VIEW_REMOTE]: ViewRemoteConnDetailModal,
|
[constants.VIEW_REMOTE]: () => <ViewRemoteConnDetailModal />,
|
||||||
[constants.EDIT_REMOTE]: EditRemoteConnModal,
|
[constants.EDIT_REMOTE]: () => <EditRemoteConnModal />,
|
||||||
[constants.ALERT]: AlertModal,
|
[constants.ALERT]: () => <AlertModal />,
|
||||||
[constants.SCREEN_SETTINGS]: ScreenSettingsModal,
|
[constants.SCREEN_SETTINGS]: () => <ScreenSettingsModal />,
|
||||||
[constants.SESSION_SETTINGS]: SessionSettingsModal,
|
[constants.SESSION_SETTINGS]: () => <SessionSettingsModal />,
|
||||||
[constants.LINE_SETTINGS]: LineSettingsModal,
|
[constants.LINE_SETTINGS]: () => <LineSettingsModal />,
|
||||||
[constants.TAB_SWITCHER]: TabSwitcherModal,
|
[constants.TAB_SWITCHER]: () => <TabSwitcherModal />,
|
||||||
[constants.USER_INPUT]: UserInputModal,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { modalsRegistry };
|
export { modalsRegistry };
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
@import "../../../app/common/themes/themes.less";
|
|
||||||
|
|
||||||
.userinput-modal {
|
|
||||||
width: 500px;
|
|
||||||
|
|
||||||
.wave-modal-content {
|
|
||||||
.wave-modal-body {
|
|
||||||
padding: 20px 20px;
|
|
||||||
|
|
||||||
.userinput-query {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
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,8 +54,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.remote-detail {
|
.remote-detail {
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.settings-field {
|
.settings-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -93,9 +91,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.terminal-wrapper {
|
.terminal-wrapper {
|
||||||
|
width: 100%;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
|
|
||||||
.terminal-connectelem {
|
.terminal-connectelem {
|
||||||
height: 163px !important; // Needed to override plugin height
|
height: 163px !important; // Needed to override plugin height
|
||||||
@@ -114,6 +111,7 @@
|
|||||||
|
|
||||||
.xterm-screen {
|
.xterm-screen {
|
||||||
padding: 10px;
|
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 { Modal, Tooltip, Button, Status } from "../elements";
|
||||||
import * as util from "../../../util/util";
|
import * as util from "../../../util/util";
|
||||||
import * as textmeasure from "../../../util/textmeasure";
|
import * as textmeasure from "../../../util/textmeasure";
|
||||||
import * as appconst from "../../appconst";
|
|
||||||
|
|
||||||
import "./viewremoteconndetail.less";
|
import "./viewremoteconndetail.less";
|
||||||
|
|
||||||
|
const RemotePtyRows = 9;
|
||||||
|
const RemotePtyCols = 80;
|
||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||||
termRef: React.RefObject<any> = React.createRef();
|
termRef: React.RefObject<any> = React.createRef();
|
||||||
@@ -291,7 +293,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
|||||||
let model = this.model;
|
let model = this.model;
|
||||||
let isTermFocused = this.model.remoteTermWrapFocus.get();
|
let isTermFocused = this.model.remoteTermWrapFocus.get();
|
||||||
let termFontSize = GlobalModel.termFontSize.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 remoteAliasText = util.isBlank(remote.remotealias) ? "(none)" : remote.remotealias;
|
||||||
let selectedRemoteStatus = this.getSelectedRemote().status;
|
let selectedRemoteStatus = this.getSelectedRemote().status;
|
||||||
|
|
||||||
@@ -369,7 +371,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
|||||||
ref={this.termRef}
|
ref={this.termRef}
|
||||||
data-remoteid={remote.remoteid}
|
data-remoteid={remote.remoteid}
|
||||||
style={{
|
style={{
|
||||||
height: textmeasure.termHeightFromRows(appconst.RemotePtyRows, termFontSize),
|
height: textmeasure.termHeightFromRows(RemotePtyRows, termFontSize),
|
||||||
width: termWidth,
|
width: termWidth,
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
+14
-21
@@ -14,7 +14,6 @@ import { sprintf } from "sprintf-js";
|
|||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { checkKeyPressed, adaptFromElectronKeyEvent, setKeyUtilPlatform } from "../util/keyutil";
|
import { checkKeyPressed, adaptFromElectronKeyEvent, setKeyUtilPlatform } from "../util/keyutil";
|
||||||
import { platform } from "os";
|
import { platform } from "os";
|
||||||
import * as T from "../types/types";
|
|
||||||
|
|
||||||
const WaveAppPathVarName = "WAVETERM_APP_PATH";
|
const WaveAppPathVarName = "WAVETERM_APP_PATH";
|
||||||
const WaveDevVarName = "WAVETERM_DEV";
|
const WaveDevVarName = "WAVETERM_DEV";
|
||||||
@@ -38,25 +37,21 @@ ensureDir(waveHome);
|
|||||||
// normalize darwin/x64 to darwin/amd64 for GOARCH compatibility
|
// normalize darwin/x64 to darwin/amd64 for GOARCH compatibility
|
||||||
let unamePlatform = process.platform;
|
let unamePlatform = process.platform;
|
||||||
let unameArch: string = process.arch;
|
let unameArch: string = process.arch;
|
||||||
``;
|
|
||||||
if (unameArch == "x64") {
|
if (unameArch == "x64") {
|
||||||
unameArch = "amd64";
|
unameArch = "amd64";
|
||||||
}
|
}
|
||||||
let logger: winston.Logger;
|
let logger;
|
||||||
let transports: winston.transport[] = [
|
let loggerConfig = {
|
||||||
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 = {
|
|
||||||
level: "info",
|
level: "info",
|
||||||
format: winston.format.combine(
|
format: winston.format.combine(
|
||||||
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
||||||
winston.format.printf((info) => `${info.timestamp} ${info.message}`)
|
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);
|
logger = winston.createLogger(loggerConfig);
|
||||||
function log(...msg) {
|
function log(...msg) {
|
||||||
try {
|
try {
|
||||||
@@ -80,7 +75,7 @@ if (isDev) {
|
|||||||
}
|
}
|
||||||
let app = electron.app;
|
let app = electron.app;
|
||||||
app.setName(isDev ? "Wave (Dev)" : "Wave");
|
app.setName(isDev ? "Wave (Dev)" : "Wave");
|
||||||
let waveSrvProc: child_process.ChildProcessWithoutNullStreams | null = null;
|
let waveSrvProc = null;
|
||||||
let waveSrvShouldRestart = false;
|
let waveSrvShouldRestart = false;
|
||||||
|
|
||||||
electron.dialog.showErrorBox = (title, content) => {
|
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
|
// don't migrate if we're running dev version or if wave home directory already exists
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let homeDir: string = process.env.HOME as string;
|
let homeDir = process.env.HOME;
|
||||||
let promptHome: string = path.join(homeDir, "prompt");
|
let promptHome = path.join(homeDir, "prompt");
|
||||||
if (!fs.existsSync(promptHome) || !fs.existsSync(path.join(promptHome, "prompt.db"))) {
|
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)
|
// make sure we have a valid prompt home directory (prompt.db must exist inside)
|
||||||
return;
|
return;
|
||||||
@@ -175,7 +170,7 @@ function readAuthKey() {
|
|||||||
return authKeyStr.trim();
|
return authKeyStr.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
let menuTemplate: (Electron.MenuItem | Electron.MenuItemConstructorOptions)[] = [
|
let menuTemplate = [
|
||||||
{
|
{
|
||||||
role: "appMenu",
|
role: "appMenu",
|
||||||
submenu: [
|
submenu: [
|
||||||
@@ -255,7 +250,7 @@ function shFrameNavHandler(event: any, url: any) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMainWindow(clientData: T.ClientDataType | null) {
|
function createMainWindow(clientData) {
|
||||||
let bounds = calcBounds(clientData);
|
let bounds = calcBounds(clientData);
|
||||||
setKeyUtilPlatform(platform());
|
setKeyUtilPlatform(platform());
|
||||||
let win = new electron.BrowserWindow({
|
let win = new electron.BrowserWindow({
|
||||||
@@ -614,9 +609,7 @@ function runWaveSrv() {
|
|||||||
pReject(new Error(sprintf("failed to start local server (%s)", waveSrvCmd)));
|
pReject(new Error(sprintf("failed to start local server (%s)", waveSrvCmd)));
|
||||||
if (waveSrvShouldRestart) {
|
if (waveSrvShouldRestart) {
|
||||||
waveSrvShouldRestart = false;
|
waveSrvShouldRestart = false;
|
||||||
// small timeout here so we can reuse the listen socket
|
this.runWaveSrv();
|
||||||
// this is normally only used in dev mode for debugging
|
|
||||||
setTimeout(runWaveSrv, 500);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
proc.on("spawn", (e) => {
|
proc.on("spawn", (e) => {
|
||||||
@@ -651,7 +644,7 @@ electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
|
|||||||
}
|
}
|
||||||
console.log("context-editmenu");
|
console.log("context-editmenu");
|
||||||
let menu = new electron.Menu();
|
let menu = new electron.Menu();
|
||||||
let menuItem: Electron.MenuItem;
|
let menuItem = null;
|
||||||
if (opts.showCut) {
|
if (opts.showCut) {
|
||||||
menuItem = new electron.MenuItem({ label: "Cut", role: "cut" });
|
menuItem = new electron.MenuItem({ label: "Cut", role: "cut" });
|
||||||
menu.append(menuItem);
|
menu.append(menuItem);
|
||||||
@@ -664,7 +657,7 @@ electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function createMainWindowWrap() {
|
async function createMainWindowWrap() {
|
||||||
let clientData: T.ClientDataType | null = null;
|
let clientData = null;
|
||||||
try {
|
try {
|
||||||
clientData = await getClientDataPoll(1);
|
clientData = await getClientDataPoll(1);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
+15
-10
@@ -13,10 +13,10 @@ import {
|
|||||||
HistoryQueryOpts,
|
HistoryQueryOpts,
|
||||||
HistoryTypeStrs,
|
HistoryTypeStrs,
|
||||||
OpenAICmdInfoChatMessageType,
|
OpenAICmdInfoChatMessageType,
|
||||||
OV,
|
|
||||||
StrWithPos,
|
|
||||||
} from "../types/types";
|
} from "../types/types";
|
||||||
|
import { StrWithPos } from "../types/types";
|
||||||
import * as appconst from "../app/appconst";
|
import * as appconst from "../app/appconst";
|
||||||
|
import { OV } from "../types/types";
|
||||||
import { Model } from "./model";
|
import { Model } from "./model";
|
||||||
import { GlobalCommandRunner } from "./global";
|
import { GlobalCommandRunner } from "./global";
|
||||||
|
|
||||||
@@ -207,6 +207,7 @@ class InputModel {
|
|||||||
this.historyQueryOpts.set(opts);
|
this.historyQueryOpts.set(opts);
|
||||||
let bestIndex = this.findBestNewIndex(oldItem);
|
let bestIndex = this.findBestNewIndex(oldItem);
|
||||||
setTimeout(() => this.setHistoryIndex(bestIndex, true), 10);
|
setTimeout(() => this.setHistoryIndex(bestIndex, true), 10);
|
||||||
|
return;
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,17 +624,13 @@ class InputModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openAIAssistantChat(): void {
|
openAIAssistantChat(): void {
|
||||||
mobx.action(() => {
|
this.aIChatShow.set(true);
|
||||||
this.aIChatShow.set(true);
|
this.setAIChatFocus();
|
||||||
this.setAIChatFocus();
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closeAIAssistantChat(): void {
|
closeAIAssistantChat(): void {
|
||||||
mobx.action(() => {
|
this.aIChatShow.set(false);
|
||||||
this.aIChatShow.set(false);
|
this.giveFocus();
|
||||||
this.giveFocus();
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearAIAssistantChat(): void {
|
clearAIAssistantChat(): void {
|
||||||
@@ -724,6 +721,14 @@ class InputModel {
|
|||||||
setCurLine(val: string): void {
|
setCurLine(val: string): void {
|
||||||
let hidx = this.historyIndex.get();
|
let hidx = this.historyIndex.get();
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
|
// if (val == "\" ") {
|
||||||
|
// this.setInputMode("comment");
|
||||||
|
// val = "";
|
||||||
|
// }
|
||||||
|
// if (val == "//") {
|
||||||
|
// this.setInputMode("global");
|
||||||
|
// val = "";
|
||||||
|
// }
|
||||||
if (this.modHistory.length <= hidx) {
|
if (this.modHistory.length <= hidx) {
|
||||||
this.modHistory.length = hidx + 1;
|
this.modHistory.length = hidx + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ import { modalsRegistry } from "../app/common/modals/registry";
|
|||||||
import { OArr } from "../types/types";
|
import { OArr } from "../types/types";
|
||||||
|
|
||||||
class ModalsModel {
|
class ModalsModel {
|
||||||
store: OArr<ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store", deep: false });
|
store: OArr<ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store" });
|
||||||
|
|
||||||
pushModal(modalId: string, props?: any) {
|
pushModal(modalId: string) {
|
||||||
const modalFactory = modalsRegistry[modalId];
|
const modalFactory = modalsRegistry[modalId];
|
||||||
|
|
||||||
if (modalFactory && !this.store.some((modal) => modal.id === modalId)) {
|
if (modalFactory && !this.store.some((modal) => modal.id === modalId)) {
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4(), props });
|
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4() });
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+243
-300
File diff suppressed because it is too large
Load Diff
@@ -51,8 +51,6 @@ import {
|
|||||||
HistoryViewDataType,
|
HistoryViewDataType,
|
||||||
AlertMessageType,
|
AlertMessageType,
|
||||||
HistorySearchParams,
|
HistorySearchParams,
|
||||||
UserInputRequest,
|
|
||||||
UserInputResponsePacket,
|
|
||||||
FocusTypeStrs,
|
FocusTypeStrs,
|
||||||
ScreenLinesType,
|
ScreenLinesType,
|
||||||
HistoryTypeStrs,
|
HistoryTypeStrs,
|
||||||
@@ -3378,14 +3376,14 @@ class RemotesModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ModalsModel {
|
class ModalsModel {
|
||||||
store: OArr<T.ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store", deep: false });
|
store: OArr<T.ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store" });
|
||||||
|
|
||||||
pushModal(modalId: string, props?: any) {
|
pushModal(modalId: string) {
|
||||||
const modalFactory = modalsRegistry[modalId];
|
const modalFactory = modalsRegistry[modalId];
|
||||||
|
|
||||||
if (modalFactory && !this.store.some((modal) => modal.id === modalId)) {
|
if (modalFactory && !this.store.some((modal) => modal.id === modalId)) {
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4(), props: props });
|
this.store.push({ id: modalId, component: modalFactory, uniqueKey: uuidv4() });
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4186,10 +4184,6 @@ class Model {
|
|||||||
this.getScreenById_single(snc.screenid)?.setNumRunningCmds(snc.num);
|
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 {
|
updateRemotes(remotes: RemoteType[]): void {
|
||||||
@@ -4597,10 +4591,6 @@ class Model {
|
|||||||
this.ws.pushMessage(inputPacket);
|
this.ws.pushMessage(inputPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendUserInput(userInputResponsePacket: UserInputResponsePacket) {
|
|
||||||
this.ws.pushMessage(userInputResponsePacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendCmdInputText(screenId: string, sp: T.StrWithPos) {
|
sendCmdInputText(screenId: string, sp: T.StrWithPos) {
|
||||||
let pk: T.CmdInputTextPacketType = {
|
let pk: T.CmdInputTextPacketType = {
|
||||||
type: "cmdinputtext",
|
type: "cmdinputtext",
|
||||||
@@ -12,6 +12,9 @@ import { GlobalCommandRunner } from "./global";
|
|||||||
import { Model } from "./model";
|
import { Model } from "./model";
|
||||||
import { getTermPtyData } from "../util/modelutil";
|
import { getTermPtyData } from "../util/modelutil";
|
||||||
|
|
||||||
|
const RemotePtyRows = 8; // also in main.tsx
|
||||||
|
const RemotePtyCols = 80;
|
||||||
|
|
||||||
class RemotesModel {
|
class RemotesModel {
|
||||||
globalModel: Model;
|
globalModel: Model;
|
||||||
selectedRemoteId: OV<string> = mobx.observable.box(null, {
|
selectedRemoteId: OV<string> = mobx.observable.box(null, {
|
||||||
@@ -177,14 +180,14 @@ class RemotesModel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let termOpts = {
|
let termOpts = {
|
||||||
rows: appconst.RemotePtyRows,
|
rows: RemotePtyRows,
|
||||||
cols: appconst.RemotePtyCols,
|
cols: RemotePtyCols,
|
||||||
flexrows: false,
|
flexrows: false,
|
||||||
maxptysize: 64 * 1024,
|
maxptysize: 64 * 1024,
|
||||||
};
|
};
|
||||||
let termWrap = new TermWrap(elem, {
|
let termWrap = new TermWrap(elem, {
|
||||||
termContext: { remoteId: remoteId },
|
termContext: { remoteId: remoteId },
|
||||||
usedRows: appconst.RemotePtyRows,
|
usedRows: RemotePtyRows,
|
||||||
termOpts: termOpts,
|
termOpts: termOpts,
|
||||||
winSize: null,
|
winSize: null,
|
||||||
keyHandler: (e, termWrap) => {
|
keyHandler: (e, termWrap) => {
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ class ScreenLines {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let lineIdx = 0;
|
let lineIdx = 0;
|
||||||
for (lineIdx; lineIdx < lines.length; lineIdx++) {
|
for (lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
||||||
let lineId = lines[lineIdx].lineid;
|
let lineId = lines[lineIdx].lineid;
|
||||||
let curTs = lines[lineIdx].ts;
|
let curTs = lines[lineIdx].ts;
|
||||||
if (lineId == line.lineid) {
|
if (lineId == line.lineid) {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
.terminal-wrapper {
|
.terminal-wrapper {
|
||||||
.xterm-viewport {
|
.xterm-viewport {
|
||||||
overflow: hidden;
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
&:hover .xterm-viewport,
|
&:hover .xterm-viewport,
|
||||||
&:focus-within .xterm-viewport {
|
&:focus-within .xterm-viewport {
|
||||||
overflow: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-66
@@ -29,6 +29,7 @@ type SessionDataType = {
|
|||||||
|
|
||||||
// for updates
|
// for updates
|
||||||
remove?: boolean;
|
remove?: boolean;
|
||||||
|
full?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LineStateType = { [k: string]: any };
|
type LineStateType = { [k: string]: any };
|
||||||
@@ -91,6 +92,7 @@ type ScreenDataType = {
|
|||||||
anchor: { anchorline: number; anchoroffset: number };
|
anchor: { anchorline: number; anchoroffset: number };
|
||||||
|
|
||||||
// for updates
|
// for updates
|
||||||
|
full?: boolean;
|
||||||
remove?: boolean;
|
remove?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -258,11 +260,6 @@ type CmdDataType = {
|
|||||||
restarted?: boolean;
|
restarted?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LineUpdateType = {
|
|
||||||
line: LineType;
|
|
||||||
cmd: CmdDataType;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PtyDataUpdateType = {
|
type PtyDataUpdateType = {
|
||||||
screenid: string;
|
screenid: string;
|
||||||
lineid: string;
|
lineid: string;
|
||||||
@@ -312,48 +309,30 @@ type ScreenNumRunningCommandsUpdateType = {
|
|||||||
num: number;
|
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 = {
|
type ModelUpdateType = {
|
||||||
interactive: boolean;
|
interactive: boolean;
|
||||||
session?: SessionDataType;
|
sessions?: SessionDataType[];
|
||||||
activesessionid?: string;
|
activesessionid?: string;
|
||||||
screen?: ScreenDataType;
|
screens?: ScreenDataType[];
|
||||||
screenlines?: ScreenLinesType;
|
screenlines?: ScreenLinesType;
|
||||||
line?: LineUpdateType;
|
line?: LineType;
|
||||||
|
lines?: LineType[];
|
||||||
cmd?: CmdDataType;
|
cmd?: CmdDataType;
|
||||||
info?: InfoType;
|
info?: InfoType;
|
||||||
cmdline?: StrWithPos;
|
cmdline?: StrWithPos;
|
||||||
remote?: RemoteType;
|
remotes?: RemoteType[];
|
||||||
history?: HistoryInfoType;
|
history?: HistoryInfoType;
|
||||||
connect?: ConnectUpdateType;
|
connect?: boolean;
|
||||||
mainview?: MainViewUpdateType;
|
mainview?: string;
|
||||||
bookmarks?: BookmarksUpdateType;
|
bookmarks?: BookmarkType[];
|
||||||
|
selectedbookmark?: string;
|
||||||
clientdata?: ClientDataType;
|
clientdata?: ClientDataType;
|
||||||
|
historyviewdata?: HistoryViewDataType;
|
||||||
remoteview?: RemoteViewType;
|
remoteview?: RemoteViewType;
|
||||||
openaicmdinfochat?: OpenAICmdInfoChatMessageType[];
|
openaicmdinfochat?: OpenAICmdInfoChatMessageType[];
|
||||||
alertmessage?: AlertMessageType;
|
alertmessage?: AlertMessageType;
|
||||||
screenstatusindicator?: ScreenStatusIndicatorUpdateType;
|
screenstatusindicators?: ScreenStatusIndicatorUpdateType[];
|
||||||
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType;
|
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType[];
|
||||||
userinputrequest?: UserInputRequest;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type HistoryViewDataType = {
|
type HistoryViewDataType = {
|
||||||
@@ -435,7 +414,7 @@ type ContextMenuOpts = {
|
|||||||
showCut?: boolean;
|
showCut?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type UpdateMessage = PtyDataUpdateType | ModelUpdateType[];
|
type UpdateMessage = PtyDataUpdateType | ModelUpdateType;
|
||||||
|
|
||||||
type RendererContext = {
|
type RendererContext = {
|
||||||
screenId: string;
|
screenId: string;
|
||||||
@@ -560,14 +539,6 @@ type ReleaseInfoType = {
|
|||||||
latestversion: string;
|
latestversion: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ClientWinSizeType = {
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
fullscreen: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ClientDataType = {
|
type ClientDataType = {
|
||||||
clientid: string;
|
clientid: string;
|
||||||
userid: string;
|
userid: string;
|
||||||
@@ -577,7 +548,6 @@ type ClientDataType = {
|
|||||||
dbversion: number;
|
dbversion: number;
|
||||||
openaiopts?: OpenAIOptsType;
|
openaiopts?: OpenAIOptsType;
|
||||||
releaseinfo?: ReleaseInfoType;
|
releaseinfo?: ReleaseInfoType;
|
||||||
winsize: ClientWinSizeType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type OpenAIOptsType = {
|
type OpenAIOptsType = {
|
||||||
@@ -625,23 +595,6 @@ type HistorySearchParams = {
|
|||||||
filterCmds?: boolean;
|
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 RenderModeType = "normal" | "collapsed" | "expanded";
|
||||||
|
|
||||||
type WebScreen = {
|
type WebScreen = {
|
||||||
@@ -777,7 +730,6 @@ type ModalStoreEntry = {
|
|||||||
id: string;
|
id: string;
|
||||||
component: React.ComponentType;
|
component: React.ComponentType;
|
||||||
uniqueKey: string;
|
uniqueKey: string;
|
||||||
props?: any;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type StrWithPos = {
|
type StrWithPos = {
|
||||||
@@ -857,8 +809,6 @@ export type {
|
|||||||
RenderModeType,
|
RenderModeType,
|
||||||
AlertMessageType,
|
AlertMessageType,
|
||||||
HistorySearchParams,
|
HistorySearchParams,
|
||||||
UserInputRequest,
|
|
||||||
UserInputResponsePacket,
|
|
||||||
ScreenLinesType,
|
ScreenLinesType,
|
||||||
FocusTypeStrs,
|
FocusTypeStrs,
|
||||||
HistoryTypeStrs,
|
HistoryTypeStrs,
|
||||||
@@ -895,7 +845,6 @@ export type {
|
|||||||
CmdInputTextPacketType,
|
CmdInputTextPacketType,
|
||||||
OpenAICmdInfoChatMessageType,
|
OpenAICmdInfoChatMessageType,
|
||||||
ScreenStatusIndicatorUpdateType,
|
ScreenStatusIndicatorUpdateType,
|
||||||
ScreenNumRunningCommandsUpdateType,
|
|
||||||
OV,
|
OV,
|
||||||
OArr,
|
OArr,
|
||||||
OMap,
|
OMap,
|
||||||
|
|||||||
+69
-53
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2023, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import * as mobx from "mobx";
|
import * as mobx from "mobx";
|
||||||
@@ -17,7 +17,7 @@ function isBlank(s: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleNotOkResp(resp: any, url: URL): Promise<any> {
|
function handleNotOkResp(resp: any, url: URL): Promise<any> {
|
||||||
const errMsg = sprintf(
|
let errMsg = sprintf(
|
||||||
"Bad status code response from fetch '%s': code=%d %s",
|
"Bad status code response from fetch '%s': code=%d %s",
|
||||||
url.toString(),
|
url.toString(),
|
||||||
resp.status,
|
resp.status,
|
||||||
@@ -41,18 +41,18 @@ function handleNotOkResp(resp: any, url: URL): Promise<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fetchJsonData(resp: any, ctErr: boolean): Promise<any> {
|
function fetchJsonData(resp: any, ctErr: boolean): Promise<any> {
|
||||||
const contentType = resp.headers.get("Content-Type");
|
let contentType = resp.headers.get("Content-Type");
|
||||||
if (contentType?.startsWith("application/json")) {
|
if (contentType != null && contentType.startsWith("application/json")) {
|
||||||
return resp.text().then((textData) => {
|
return resp.text().then((textData) => {
|
||||||
let rtnData: any = null;
|
let rtnData: any = null;
|
||||||
try {
|
try {
|
||||||
rtnData = JSON.parse(textData);
|
rtnData = JSON.parse(textData);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errMsg = sprintf("Unparseable JSON: " + err.message);
|
let errMsg = sprintf("Unparseable JSON: " + err.message);
|
||||||
const rtnErr = new Error(errMsg);
|
let rtnErr = new Error(errMsg);
|
||||||
throw rtnErr;
|
throw rtnErr;
|
||||||
}
|
}
|
||||||
if (rtnData?.error) {
|
if (rtnData != null && rtnData.error) {
|
||||||
throw new Error(rtnData.error);
|
throw new Error(rtnData.error);
|
||||||
}
|
}
|
||||||
return rtnData;
|
return rtnData;
|
||||||
@@ -67,23 +67,23 @@ function handleJsonFetchResponse(url: URL, resp: any): Promise<any> {
|
|||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
return handleNotOkResp(resp, url);
|
return handleNotOkResp(resp, url);
|
||||||
}
|
}
|
||||||
const rtnData = fetchJsonData(resp, true);
|
let rtnData = fetchJsonData(resp, true);
|
||||||
return rtnData;
|
return rtnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
function base64ToString(b64: string): string {
|
function base64ToString(b64: string): string {
|
||||||
const stringBytes = base64.toByteArray(b64);
|
let stringBytes = base64.toByteArray(b64);
|
||||||
return new TextDecoder().decode(stringBytes);
|
return new TextDecoder().decode(stringBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringToBase64(input: string): string {
|
function stringToBase64(input: string): string {
|
||||||
const stringBytes = new TextEncoder().encode(input);
|
let stringBytes = new TextEncoder().encode(input);
|
||||||
return base64.fromByteArray(stringBytes);
|
return base64.fromByteArray(stringBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function base64ToArray(b64: string): Uint8Array {
|
function base64ToArray(b64: string): Uint8Array {
|
||||||
const rawStr = atob(b64);
|
let rawStr = atob(b64);
|
||||||
const rtnArr = new Uint8Array(new ArrayBuffer(rawStr.length));
|
let rtnArr = new Uint8Array(new ArrayBuffer(rawStr.length));
|
||||||
for (let i = 0; i < rawStr.length; i++) {
|
for (let i = 0; i < rawStr.length; i++) {
|
||||||
rtnArr[i] = rawStr.charCodeAt(i);
|
rtnArr[i] = rawStr.charCodeAt(i);
|
||||||
}
|
}
|
||||||
@@ -92,6 +92,7 @@ function base64ToArray(b64: string): Uint8Array {
|
|||||||
|
|
||||||
interface IDataType {
|
interface IDataType {
|
||||||
remove?: boolean;
|
remove?: boolean;
|
||||||
|
full?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IObjType<DataType> {
|
interface IObjType<DataType> {
|
||||||
@@ -112,28 +113,31 @@ function genMergeSimpleData<T extends ISimpleDataType>(
|
|||||||
if (dataArr == null || dataArr.length == 0) {
|
if (dataArr == null || dataArr.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const objMap: Record<string, T> = {};
|
let objMap: Record<string, T> = {};
|
||||||
for (const obj of objs) {
|
for (let i = 0; i < objs.length; i++) {
|
||||||
const id = idFn(obj);
|
let obj = objs[i];
|
||||||
|
let id = idFn(obj);
|
||||||
objMap[id] = obj;
|
objMap[id] = obj;
|
||||||
}
|
}
|
||||||
for (const dataItem of dataArr) {
|
for (let i = 0; i < dataArr.length; i++) {
|
||||||
|
let dataItem = dataArr[i];
|
||||||
if (dataItem == null) {
|
if (dataItem == null) {
|
||||||
console.log("genMergeSimpleData, null item");
|
console.log("genMergeSimpleData, null item");
|
||||||
console.trace();
|
console.trace();
|
||||||
}
|
}
|
||||||
const id = idFn(dataItem);
|
let id = idFn(dataItem);
|
||||||
if (dataItem.remove) {
|
if (dataItem.remove) {
|
||||||
delete objMap[id];
|
delete objMap[id];
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
objMap[id] = dataItem;
|
objMap[id] = dataItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const newObjs = Object.values(objMap);
|
let newObjs = Object.values(objMap);
|
||||||
if (sortIdxFn) {
|
if (sortIdxFn) {
|
||||||
newObjs.sort((a, b) => {
|
newObjs.sort((a, b) => {
|
||||||
const astr = sortIdxFn(a);
|
let astr = sortIdxFn(a);
|
||||||
const bstr = sortIdxFn(b);
|
let bstr = sortIdxFn(b);
|
||||||
return astr.localeCompare(bstr);
|
return astr.localeCompare(bstr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -151,18 +155,20 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
|
|||||||
if (dataArr == null || dataArr.length == 0) {
|
if (dataArr == null || dataArr.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const objMap: Record<string, ObjType> = {};
|
let objMap: Record<string, ObjType> = {};
|
||||||
for (const obj of objs) {
|
for (let i = 0; i < objs.length; i++) {
|
||||||
const id = objIdFn(obj);
|
let obj = objs[i];
|
||||||
|
let id = objIdFn(obj);
|
||||||
objMap[id] = obj;
|
objMap[id] = obj;
|
||||||
}
|
}
|
||||||
for (const dataItem of dataArr) {
|
for (let i = 0; i < dataArr.length; i++) {
|
||||||
|
let dataItem = dataArr[i];
|
||||||
if (dataItem == null) {
|
if (dataItem == null) {
|
||||||
console.log("genMergeData, null item");
|
console.log("genMergeData, null item");
|
||||||
console.trace();
|
console.trace();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const id = dataIdFn(dataItem);
|
let id = dataIdFn(dataItem);
|
||||||
let obj = objMap[id];
|
let obj = objMap[id];
|
||||||
if (dataItem.remove) {
|
if (dataItem.remove) {
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
@@ -172,13 +178,17 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
|
if (!dataItem.full) {
|
||||||
|
console.log("cannot create object, dataitem is not full", objs, dataItem);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
obj = ctorFn(dataItem);
|
obj = ctorFn(dataItem);
|
||||||
objMap[id] = obj;
|
objMap[id] = obj;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
obj.mergeData(dataItem);
|
obj.mergeData(dataItem);
|
||||||
}
|
}
|
||||||
const newObjs = Object.values(objMap);
|
let newObjs = Object.values(objMap);
|
||||||
if (sortIdxFn) {
|
if (sortIdxFn) {
|
||||||
newObjs.sort((a, b) => {
|
newObjs.sort((a, b) => {
|
||||||
return sortIdxFn(a) - sortIdxFn(b);
|
return sortIdxFn(a) - sortIdxFn(b);
|
||||||
@@ -194,17 +204,18 @@ function genMergeDataMap<ObjType extends IObjType<DataType>, DataType extends ID
|
|||||||
dataIdFn: (data: DataType) => string,
|
dataIdFn: (data: DataType) => string,
|
||||||
ctorFn: (data: DataType) => ObjType
|
ctorFn: (data: DataType) => ObjType
|
||||||
): { added: string[]; removed: string[] } {
|
): { 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) {
|
if (dataArr == null || dataArr.length == 0) {
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
for (const dataItem of dataArr) {
|
for (let i = 0; i < dataArr.length; i++) {
|
||||||
|
let dataItem = dataArr[i];
|
||||||
if (dataItem == null) {
|
if (dataItem == null) {
|
||||||
console.log("genMergeDataMap, null item");
|
console.log("genMergeDataMap, null item");
|
||||||
console.trace();
|
console.trace();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const id = dataIdFn(dataItem);
|
let id = dataIdFn(dataItem);
|
||||||
let obj = objMap.get(id);
|
let obj = objMap.get(id);
|
||||||
if (dataItem.remove) {
|
if (dataItem.remove) {
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
@@ -215,6 +226,10 @@ function genMergeDataMap<ObjType extends IObjType<DataType>, DataType extends ID
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
|
if (!dataItem.full) {
|
||||||
|
console.log("cannot create object, dataitem is not full", dataItem);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
obj = ctorFn(dataItem);
|
obj = ctorFn(dataItem);
|
||||||
objMap.set(id, obj);
|
objMap.set(id, obj);
|
||||||
rtn.added.push(id);
|
rtn.added.push(id);
|
||||||
@@ -247,23 +262,23 @@ function incObs(inum: mobx.IObservableValue<number>) {
|
|||||||
|
|
||||||
// @check:font
|
// @check:font
|
||||||
function loadFonts() {
|
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",
|
style: "normal",
|
||||||
weight: "400",
|
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",
|
style: "normal",
|
||||||
weight: "200",
|
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",
|
style: "normal",
|
||||||
weight: "700",
|
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",
|
style: "normal",
|
||||||
weight: "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(jbmFontNormal);
|
||||||
docFonts.add(jbmFont200);
|
docFonts.add(jbmFont200);
|
||||||
docFonts.add(jbmFont700);
|
docFonts.add(jbmFont700);
|
||||||
@@ -281,13 +296,13 @@ function getTodayStr(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getYesterdayStr(): string {
|
function getYesterdayStr(): string {
|
||||||
const d = new Date();
|
let d = new Date();
|
||||||
d.setDate(d.getDate() - 1);
|
d.setDate(d.getDate() - 1);
|
||||||
return getDateStr(d);
|
return getDateStr(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDateStr(d: Date): string {
|
function getDateStr(d: Date): string {
|
||||||
const yearStr = String(d.getFullYear());
|
let yearStr = String(d.getFullYear());
|
||||||
let monthStr = String(d.getMonth() + 1);
|
let monthStr = String(d.getMonth() + 1);
|
||||||
if (monthStr.length == 1) {
|
if (monthStr.length == 1) {
|
||||||
monthStr = "0" + monthStr;
|
monthStr = "0" + monthStr;
|
||||||
@@ -296,30 +311,31 @@ function getDateStr(d: Date): string {
|
|||||||
if (dayStr.length == 1) {
|
if (dayStr.length == 1) {
|
||||||
dayStr = "0" + dayStr;
|
dayStr = "0" + dayStr;
|
||||||
}
|
}
|
||||||
const dowStr = DOW_STRS[d.getDay()];
|
let dowStr = DOW_STRS[d.getDay()];
|
||||||
return dowStr + " " + yearStr + "-" + monthStr + "-" + dayStr;
|
return dowStr + " " + yearStr + "-" + monthStr + "-" + dayStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRemoteConnVal(r: RemoteType): number {
|
function getRemoteConnVal(r: RemoteType): number {
|
||||||
switch (r.status) {
|
if (r.status == "connected") {
|
||||||
case "connected":
|
return 1;
|
||||||
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[] {
|
function sortAndFilterRemotes(origRemotes: RemoteType[]): RemoteType[] {
|
||||||
const remotes = origRemotes.filter((r) => !r.archived);
|
let remotes = origRemotes.filter((r) => !r.archived);
|
||||||
remotes.sort((a, b) => {
|
remotes.sort((a, b) => {
|
||||||
const connValA = getRemoteConnVal(a);
|
let connValA = getRemoteConnVal(a);
|
||||||
const connValB = getRemoteConnVal(b);
|
let connValB = getRemoteConnVal(b);
|
||||||
if (connValA != connValB) {
|
if (connValA != connValB) {
|
||||||
return connValA - connValB;
|
return connValA - connValB;
|
||||||
}
|
}
|
||||||
@@ -356,7 +372,7 @@ function openLink(url: string): void {
|
|||||||
window.open(url, "_blank");
|
window.open(url, "_blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getColorRGB(colorInput: string) {
|
function getColorRGB(colorInput) {
|
||||||
const tempElement = document.createElement("div");
|
const tempElement = document.createElement("div");
|
||||||
tempElement.style.color = colorInput;
|
tempElement.style.color = colorInput;
|
||||||
document.body.appendChild(tempElement);
|
document.body.appendChild(tempElement);
|
||||||
@@ -383,7 +399,7 @@ function getRemoteName(remote: RemoteType): string {
|
|||||||
if (remote == null) {
|
if (remote == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const { remotealias, remotecanonicalname } = remote;
|
let { remotealias, remotecanonicalname } = remote;
|
||||||
return remotealias ? `${remotealias} [${remotecanonicalname}]` : remotecanonicalname;
|
return remotealias ? `${remotealias} [${remotecanonicalname}]` : remotecanonicalname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user