mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c06d846efe | |||
| 2a4d85430a | |||
| d319e72609 | |||
| 7a5afccab3 | |||
| efe567398a | |||
| 187509504d | |||
| 903b26bfca | |||
| e692c7c180 | |||
| b37f7f722e |
@@ -8,6 +8,7 @@ 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,6 +5,7 @@
|
|||||||
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,7 +60,13 @@ class PasswordField extends TextField {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
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}</>}
|
{decoration?.startDecoration && <>{decoration.startDecoration}</>}
|
||||||
<div className="wave-textfield-inner">
|
<div className="wave-textfield-inner">
|
||||||
<label
|
<label
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ 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} />);
|
rtn.push(<Comp key={entry.uniqueKey} {...entry.props} />);
|
||||||
}
|
}
|
||||||
return <>{rtn}</>;
|
return <>{rtn}</>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,19 +12,21 @@ 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.ReactElement } = {
|
const modalsRegistry: { [key: string]: React.ComponentType } = {
|
||||||
[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 };
|
||||||
|
|||||||
@@ -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 {
|
.remote-detail {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
.settings-field {
|
.settings-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -91,8 +93,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.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
|
||||||
@@ -111,7 +114,6 @@
|
|||||||
|
|
||||||
.xterm-screen {
|
.xterm-screen {
|
||||||
padding: 10px;
|
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 { 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();
|
||||||
@@ -293,7 +291,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(RemotePtyCols, termFontSize);
|
let termWidth = textmeasure.termWidthFromCols(appconst.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;
|
||||||
|
|
||||||
@@ -371,7 +369,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(RemotePtyRows, termFontSize),
|
height: textmeasure.termHeightFromRows(appconst.RemotePtyRows, termFontSize),
|
||||||
width: termWidth,
|
width: termWidth,
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
+21
-14
@@ -14,6 +14,7 @@ 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";
|
||||||
@@ -37,21 +38,25 @@ 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;
|
let logger: winston.Logger;
|
||||||
let loggerConfig = {
|
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 = {
|
||||||
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: [new winston.transports.File({ filename: path.join(waveHome, "waveterm-app.log"), level: "info" })],
|
transports: transports,
|
||||||
};
|
};
|
||||||
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 {
|
||||||
@@ -75,7 +80,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 = null;
|
let waveSrvProc: child_process.ChildProcessWithoutNullStreams | null = null;
|
||||||
let waveSrvShouldRestart = false;
|
let waveSrvShouldRestart = false;
|
||||||
|
|
||||||
electron.dialog.showErrorBox = (title, content) => {
|
electron.dialog.showErrorBox = (title, content) => {
|
||||||
@@ -101,8 +106,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 = process.env.HOME;
|
let homeDir: string = process.env.HOME as string;
|
||||||
let promptHome = path.join(homeDir, "prompt");
|
let promptHome: string = 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;
|
||||||
@@ -170,7 +175,7 @@ function readAuthKey() {
|
|||||||
return authKeyStr.trim();
|
return authKeyStr.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
let menuTemplate = [
|
let menuTemplate: (Electron.MenuItem | Electron.MenuItemConstructorOptions)[] = [
|
||||||
{
|
{
|
||||||
role: "appMenu",
|
role: "appMenu",
|
||||||
submenu: [
|
submenu: [
|
||||||
@@ -250,7 +255,7 @@ function shFrameNavHandler(event: any, url: any) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMainWindow(clientData) {
|
function createMainWindow(clientData: T.ClientDataType | null) {
|
||||||
let bounds = calcBounds(clientData);
|
let bounds = calcBounds(clientData);
|
||||||
setKeyUtilPlatform(platform());
|
setKeyUtilPlatform(platform());
|
||||||
let win = new electron.BrowserWindow({
|
let win = new electron.BrowserWindow({
|
||||||
@@ -609,7 +614,9 @@ 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;
|
||||||
this.runWaveSrv();
|
// small timeout here so we can reuse the listen socket
|
||||||
|
// this is normally only used in dev mode for debugging
|
||||||
|
setTimeout(runWaveSrv, 500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
proc.on("spawn", (e) => {
|
proc.on("spawn", (e) => {
|
||||||
@@ -644,7 +651,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 = null;
|
let menuItem: Electron.MenuItem;
|
||||||
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);
|
||||||
@@ -657,7 +664,7 @@ electron.ipcMain.on("context-editmenu", (event, { x, y }, opts) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function createMainWindowWrap() {
|
async function createMainWindowWrap() {
|
||||||
let clientData = null;
|
let clientData: T.ClientDataType | null = null;
|
||||||
try {
|
try {
|
||||||
clientData = await getClientDataPoll(1);
|
clientData = await getClientDataPoll(1);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
+10
-15
@@ -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,7 +207,6 @@ 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;
|
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,13 +623,17 @@ class InputModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openAIAssistantChat(): void {
|
openAIAssistantChat(): void {
|
||||||
this.aIChatShow.set(true);
|
mobx.action(() => {
|
||||||
this.setAIChatFocus();
|
this.aIChatShow.set(true);
|
||||||
|
this.setAIChatFocus();
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeAIAssistantChat(): void {
|
closeAIAssistantChat(): void {
|
||||||
this.aIChatShow.set(false);
|
mobx.action(() => {
|
||||||
this.giveFocus();
|
this.aIChatShow.set(false);
|
||||||
|
this.giveFocus();
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
clearAIAssistantChat(): void {
|
clearAIAssistantChat(): void {
|
||||||
@@ -721,14 +724,6 @@ 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" });
|
store: OArr<ModalStoreEntry> = mobx.observable.array([], { name: "ModalsModel-store", deep: false });
|
||||||
|
|
||||||
pushModal(modalId: string) {
|
pushModal(modalId: string, props?: any) {
|
||||||
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() });
|
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,
|
HistoryViewDataType,
|
||||||
AlertMessageType,
|
AlertMessageType,
|
||||||
HistorySearchParams,
|
HistorySearchParams,
|
||||||
|
UserInputRequest,
|
||||||
|
UserInputResponsePacket,
|
||||||
FocusTypeStrs,
|
FocusTypeStrs,
|
||||||
ScreenLinesType,
|
ScreenLinesType,
|
||||||
HistoryTypeStrs,
|
HistoryTypeStrs,
|
||||||
@@ -3376,14 +3378,14 @@ class RemotesModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ModalsModel {
|
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];
|
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() });
|
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);
|
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 {
|
||||||
@@ -4591,6 +4597,10 @@ 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,9 +12,6 @@ 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, {
|
||||||
@@ -180,14 +177,14 @@ class RemotesModel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let termOpts = {
|
let termOpts = {
|
||||||
rows: RemotePtyRows,
|
rows: appconst.RemotePtyRows,
|
||||||
cols: RemotePtyCols,
|
cols: appconst.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: RemotePtyRows,
|
usedRows: appconst.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 = 0; lineIdx < lines.length; lineIdx++) {
|
for (lineIdx; 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-y: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
&:hover .xterm-viewport,
|
&:hover .xterm-viewport,
|
||||||
&:focus-within .xterm-viewport {
|
&:focus-within .xterm-viewport {
|
||||||
overflow-y: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+66
-15
@@ -29,7 +29,6 @@ type SessionDataType = {
|
|||||||
|
|
||||||
// for updates
|
// for updates
|
||||||
remove?: boolean;
|
remove?: boolean;
|
||||||
full?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type LineStateType = { [k: string]: any };
|
type LineStateType = { [k: string]: any };
|
||||||
@@ -92,7 +91,6 @@ type ScreenDataType = {
|
|||||||
anchor: { anchorline: number; anchoroffset: number };
|
anchor: { anchorline: number; anchoroffset: number };
|
||||||
|
|
||||||
// for updates
|
// for updates
|
||||||
full?: boolean;
|
|
||||||
remove?: boolean;
|
remove?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -260,6 +258,11 @@ type CmdDataType = {
|
|||||||
restarted?: boolean;
|
restarted?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LineUpdateType = {
|
||||||
|
line: LineType;
|
||||||
|
cmd: CmdDataType;
|
||||||
|
};
|
||||||
|
|
||||||
type PtyDataUpdateType = {
|
type PtyDataUpdateType = {
|
||||||
screenid: string;
|
screenid: string;
|
||||||
lineid: string;
|
lineid: string;
|
||||||
@@ -309,30 +312,48 @@ 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;
|
||||||
sessions?: SessionDataType[];
|
session?: SessionDataType;
|
||||||
activesessionid?: string;
|
activesessionid?: string;
|
||||||
screens?: ScreenDataType[];
|
screen?: ScreenDataType;
|
||||||
screenlines?: ScreenLinesType;
|
screenlines?: ScreenLinesType;
|
||||||
line?: LineType;
|
line?: LineUpdateType;
|
||||||
lines?: LineType[];
|
|
||||||
cmd?: CmdDataType;
|
cmd?: CmdDataType;
|
||||||
info?: InfoType;
|
info?: InfoType;
|
||||||
cmdline?: StrWithPos;
|
cmdline?: StrWithPos;
|
||||||
remotes?: RemoteType[];
|
remote?: RemoteType;
|
||||||
history?: HistoryInfoType;
|
history?: HistoryInfoType;
|
||||||
connect?: boolean;
|
connect?: ConnectUpdateType;
|
||||||
mainview?: string;
|
mainview?: MainViewUpdateType;
|
||||||
bookmarks?: BookmarkType[];
|
bookmarks?: BookmarksUpdateType;
|
||||||
selectedbookmark?: string;
|
|
||||||
clientdata?: ClientDataType;
|
clientdata?: ClientDataType;
|
||||||
historyviewdata?: HistoryViewDataType;
|
|
||||||
remoteview?: RemoteViewType;
|
remoteview?: RemoteViewType;
|
||||||
openaicmdinfochat?: OpenAICmdInfoChatMessageType[];
|
openaicmdinfochat?: OpenAICmdInfoChatMessageType[];
|
||||||
alertmessage?: AlertMessageType;
|
alertmessage?: AlertMessageType;
|
||||||
screenstatusindicators?: ScreenStatusIndicatorUpdateType[];
|
screenstatusindicator?: ScreenStatusIndicatorUpdateType;
|
||||||
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType[];
|
screennumrunningcommands?: ScreenNumRunningCommandsUpdateType;
|
||||||
|
userinputrequest?: UserInputRequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
type HistoryViewDataType = {
|
type HistoryViewDataType = {
|
||||||
@@ -414,7 +435,7 @@ type ContextMenuOpts = {
|
|||||||
showCut?: boolean;
|
showCut?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type UpdateMessage = PtyDataUpdateType | ModelUpdateType;
|
type UpdateMessage = PtyDataUpdateType | ModelUpdateType[];
|
||||||
|
|
||||||
type RendererContext = {
|
type RendererContext = {
|
||||||
screenId: string;
|
screenId: string;
|
||||||
@@ -539,6 +560,14 @@ 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;
|
||||||
@@ -548,6 +577,7 @@ type ClientDataType = {
|
|||||||
dbversion: number;
|
dbversion: number;
|
||||||
openaiopts?: OpenAIOptsType;
|
openaiopts?: OpenAIOptsType;
|
||||||
releaseinfo?: ReleaseInfoType;
|
releaseinfo?: ReleaseInfoType;
|
||||||
|
winsize: ClientWinSizeType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OpenAIOptsType = {
|
type OpenAIOptsType = {
|
||||||
@@ -595,6 +625,23 @@ 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 = {
|
||||||
@@ -730,6 +777,7 @@ type ModalStoreEntry = {
|
|||||||
id: string;
|
id: string;
|
||||||
component: React.ComponentType;
|
component: React.ComponentType;
|
||||||
uniqueKey: string;
|
uniqueKey: string;
|
||||||
|
props?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StrWithPos = {
|
type StrWithPos = {
|
||||||
@@ -809,6 +857,8 @@ export type {
|
|||||||
RenderModeType,
|
RenderModeType,
|
||||||
AlertMessageType,
|
AlertMessageType,
|
||||||
HistorySearchParams,
|
HistorySearchParams,
|
||||||
|
UserInputRequest,
|
||||||
|
UserInputResponsePacket,
|
||||||
ScreenLinesType,
|
ScreenLinesType,
|
||||||
FocusTypeStrs,
|
FocusTypeStrs,
|
||||||
HistoryTypeStrs,
|
HistoryTypeStrs,
|
||||||
@@ -845,6 +895,7 @@ export type {
|
|||||||
CmdInputTextPacketType,
|
CmdInputTextPacketType,
|
||||||
OpenAICmdInfoChatMessageType,
|
OpenAICmdInfoChatMessageType,
|
||||||
ScreenStatusIndicatorUpdateType,
|
ScreenStatusIndicatorUpdateType,
|
||||||
|
ScreenNumRunningCommandsUpdateType,
|
||||||
OV,
|
OV,
|
||||||
OArr,
|
OArr,
|
||||||
OMap,
|
OMap,
|
||||||
|
|||||||
+53
-69
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2023, Command Line Inc.
|
// Copyright 2024, 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> {
|
||||||
let errMsg = sprintf(
|
const 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> {
|
||||||
let contentType = resp.headers.get("Content-Type");
|
const contentType = resp.headers.get("Content-Type");
|
||||||
if (contentType != null && contentType.startsWith("application/json")) {
|
if (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) {
|
||||||
let errMsg = sprintf("Unparseable JSON: " + err.message);
|
const errMsg = sprintf("Unparseable JSON: " + err.message);
|
||||||
let rtnErr = new Error(errMsg);
|
const rtnErr = new Error(errMsg);
|
||||||
throw rtnErr;
|
throw rtnErr;
|
||||||
}
|
}
|
||||||
if (rtnData != null && rtnData.error) {
|
if (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);
|
||||||
}
|
}
|
||||||
let rtnData = fetchJsonData(resp, true);
|
const rtnData = fetchJsonData(resp, true);
|
||||||
return rtnData;
|
return rtnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
function base64ToString(b64: string): string {
|
function base64ToString(b64: string): string {
|
||||||
let stringBytes = base64.toByteArray(b64);
|
const stringBytes = base64.toByteArray(b64);
|
||||||
return new TextDecoder().decode(stringBytes);
|
return new TextDecoder().decode(stringBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringToBase64(input: string): string {
|
function stringToBase64(input: string): string {
|
||||||
let stringBytes = new TextEncoder().encode(input);
|
const stringBytes = new TextEncoder().encode(input);
|
||||||
return base64.fromByteArray(stringBytes);
|
return base64.fromByteArray(stringBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function base64ToArray(b64: string): Uint8Array {
|
function base64ToArray(b64: string): Uint8Array {
|
||||||
let rawStr = atob(b64);
|
const rawStr = atob(b64);
|
||||||
let rtnArr = new Uint8Array(new ArrayBuffer(rawStr.length));
|
const 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,7 +92,6 @@ function base64ToArray(b64: string): Uint8Array {
|
|||||||
|
|
||||||
interface IDataType {
|
interface IDataType {
|
||||||
remove?: boolean;
|
remove?: boolean;
|
||||||
full?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IObjType<DataType> {
|
interface IObjType<DataType> {
|
||||||
@@ -113,31 +112,28 @@ function genMergeSimpleData<T extends ISimpleDataType>(
|
|||||||
if (dataArr == null || dataArr.length == 0) {
|
if (dataArr == null || dataArr.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let objMap: Record<string, T> = {};
|
const objMap: Record<string, T> = {};
|
||||||
for (let i = 0; i < objs.length; i++) {
|
for (const obj of objs) {
|
||||||
let obj = objs[i];
|
const id = idFn(obj);
|
||||||
let id = idFn(obj);
|
|
||||||
objMap[id] = obj;
|
objMap[id] = obj;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < dataArr.length; i++) {
|
for (const dataItem of dataArr) {
|
||||||
let dataItem = dataArr[i];
|
|
||||||
if (dataItem == null) {
|
if (dataItem == null) {
|
||||||
console.log("genMergeSimpleData, null item");
|
console.log("genMergeSimpleData, null item");
|
||||||
console.trace();
|
console.trace();
|
||||||
}
|
}
|
||||||
let id = idFn(dataItem);
|
const id = idFn(dataItem);
|
||||||
if (dataItem.remove) {
|
if (dataItem.remove) {
|
||||||
delete objMap[id];
|
delete objMap[id];
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
objMap[id] = dataItem;
|
objMap[id] = dataItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let newObjs = Object.values(objMap);
|
const newObjs = Object.values(objMap);
|
||||||
if (sortIdxFn) {
|
if (sortIdxFn) {
|
||||||
newObjs.sort((a, b) => {
|
newObjs.sort((a, b) => {
|
||||||
let astr = sortIdxFn(a);
|
const astr = sortIdxFn(a);
|
||||||
let bstr = sortIdxFn(b);
|
const bstr = sortIdxFn(b);
|
||||||
return astr.localeCompare(bstr);
|
return astr.localeCompare(bstr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -155,20 +151,18 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
|
|||||||
if (dataArr == null || dataArr.length == 0) {
|
if (dataArr == null || dataArr.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let objMap: Record<string, ObjType> = {};
|
const objMap: Record<string, ObjType> = {};
|
||||||
for (let i = 0; i < objs.length; i++) {
|
for (const obj of objs) {
|
||||||
let obj = objs[i];
|
const id = objIdFn(obj);
|
||||||
let id = objIdFn(obj);
|
|
||||||
objMap[id] = obj;
|
objMap[id] = obj;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < dataArr.length; i++) {
|
for (const dataItem of dataArr) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
let id = dataIdFn(dataItem);
|
const id = dataIdFn(dataItem);
|
||||||
let obj = objMap[id];
|
let obj = objMap[id];
|
||||||
if (dataItem.remove) {
|
if (dataItem.remove) {
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
@@ -178,17 +172,13 @@ 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);
|
||||||
}
|
}
|
||||||
let newObjs = Object.values(objMap);
|
const 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);
|
||||||
@@ -204,18 +194,17 @@ 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[] } {
|
||||||
let rtn: { added: string[]; removed: string[] } = { added: [], removed: [] };
|
const rtn: { added: string[]; removed: string[] } = { added: [], removed: [] };
|
||||||
if (dataArr == null || dataArr.length == 0) {
|
if (dataArr == null || dataArr.length == 0) {
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < dataArr.length; i++) {
|
for (const dataItem of dataArr) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
let id = dataIdFn(dataItem);
|
const 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) {
|
||||||
@@ -226,10 +215,6 @@ 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);
|
||||||
@@ -262,23 +247,23 @@ function incObs(inum: mobx.IObservableValue<number>) {
|
|||||||
|
|
||||||
// @check:font
|
// @check:font
|
||||||
function loadFonts() {
|
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",
|
style: "normal",
|
||||||
weight: "400",
|
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",
|
style: "normal",
|
||||||
weight: "200",
|
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",
|
style: "normal",
|
||||||
weight: "700",
|
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",
|
style: "normal",
|
||||||
weight: "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(jbmFontNormal);
|
||||||
docFonts.add(jbmFont200);
|
docFonts.add(jbmFont200);
|
||||||
docFonts.add(jbmFont700);
|
docFonts.add(jbmFont700);
|
||||||
@@ -296,13 +281,13 @@ function getTodayStr(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getYesterdayStr(): string {
|
function getYesterdayStr(): string {
|
||||||
let d = new Date();
|
const 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 {
|
||||||
let yearStr = String(d.getFullYear());
|
const 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;
|
||||||
@@ -311,31 +296,30 @@ function getDateStr(d: Date): string {
|
|||||||
if (dayStr.length == 1) {
|
if (dayStr.length == 1) {
|
||||||
dayStr = "0" + dayStr;
|
dayStr = "0" + dayStr;
|
||||||
}
|
}
|
||||||
let dowStr = DOW_STRS[d.getDay()];
|
const 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 {
|
||||||
if (r.status == "connected") {
|
switch (r.status) {
|
||||||
return 1;
|
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[] {
|
function sortAndFilterRemotes(origRemotes: RemoteType[]): RemoteType[] {
|
||||||
let remotes = origRemotes.filter((r) => !r.archived);
|
const remotes = origRemotes.filter((r) => !r.archived);
|
||||||
remotes.sort((a, b) => {
|
remotes.sort((a, b) => {
|
||||||
let connValA = getRemoteConnVal(a);
|
const connValA = getRemoteConnVal(a);
|
||||||
let connValB = getRemoteConnVal(b);
|
const connValB = getRemoteConnVal(b);
|
||||||
if (connValA != connValB) {
|
if (connValA != connValB) {
|
||||||
return connValA - connValB;
|
return connValA - connValB;
|
||||||
}
|
}
|
||||||
@@ -372,7 +356,7 @@ function openLink(url: string): void {
|
|||||||
window.open(url, "_blank");
|
window.open(url, "_blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getColorRGB(colorInput) {
|
function getColorRGB(colorInput: string) {
|
||||||
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);
|
||||||
@@ -399,7 +383,7 @@ function getRemoteName(remote: RemoteType): string {
|
|||||||
if (remote == null) {
|
if (remote == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
let { remotealias, remotecanonicalname } = remote;
|
const { 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