Compare commits

...

9 Commits

Author SHA1 Message Date
sawka 14b10d0848 fix hmac implementation/typo. read WaveAuthKey and store in scbase instead of main-server 2024-03-14 00:22:30 -07:00
Mike Sawka 865658aa92 allow hmac authentication for read-file (#449) 2024-03-13 23:59:20 -07:00
Mike Sawka 4c68fc4ceb pdf viewer (#448)
* checkpoint on pdf viewer

* implement a pdf renderer (fix emain shFrameNavHandler to allow it)
2024-03-13 23:25:11 -07:00
Mike Sawka bff51c851a sync command to synchronize shell state with wave prompt (#444)
* remove two unused packet types, remove unused detatched command code

* CmdStart is invalid in this command loop

* slight refactor, remove closure funcs

* pass rct through to 'handle' funcs

* deal with rct (running command), update handler funcs accordingly

* update for runningcmdtype to be a pointer in the map (for updates)

* lots of changes related to ephemeral commands (for sync), checkpoint

* fix ephemeral setting

* sync shell state when you switch to a new tab
2024-03-13 18:52:41 -07:00
Sylvie Crowe 550d9c9716 fix: split the apple locale on the region for LANG (#447)
We use AppleLocale to get the desired language when running on macos.
Unfortunately, if a region is set, the locale is not equivalent to the
LANG environment variable. It appends an extra region field that we did
not previously filter out. This change ensures that it will be filtered
out when present.
2024-03-13 18:52:02 -07:00
Red J Adaya 9eb7461964 Close modals when pressing Escape (#433)
* remove clearmodals mothed as it's no longer needed

* close modals on ECS
2024-03-13 18:51:16 -07:00
Red J Adaya 0241e47f83 fix broken bookmarks view (#446) 2024-03-13 18:48:46 -07:00
Cole Lashley f87cc42ab9 Slash Commands for keybindings (#441)
* first pass of slash commands

* added mainview slashcommand

* added focus cmd input, added sleep

* addressed review comments

* addressed feedback

* demo idea of changing hide do cmd+m, can remove if we decide we don't like it

* added new keybinding for minimize

* addressed feedback

* added hide label

* fix hide (use app.hid(), not window.hide()

* fix history keybinding, make mainview command consistent
2024-03-13 18:47:16 -07:00
Mike Sawka fc0b82836c quick UI updates (center imageview, fix terminal cursor colors, and add firacode font) (#445)
* center imageview images

* fix terminal selection colors #442

* add firacode font
2024-03-13 16:24:47 -07:00
39 changed files with 653 additions and 1231 deletions
+32 -15
View File
@@ -3,6 +3,10 @@
"command": "system:toggleDeveloperTools",
"keys": ["Cmd:Option:i"]
},
{
"command": "system:hideWindow",
"keys": ["Cmd:m"]
},
{
"command": "generic:cancel",
"keys": ["Escape"]
@@ -32,7 +36,7 @@
"keys": ["PageDown"]
},
{
"command": "app:openHistory",
"command": "app:openHistoryView",
"keys": ["Cmd:h"]
},
{
@@ -41,11 +45,13 @@
},
{
"command": "app:openConnectionsView",
"keys": []
"keys": [],
"commandStr": "/mainview connections"
},
{
"command": "app:openSettingsView",
"keys": []
"keys": [],
"commandStr": "/mainview clientsettings"
},
{
"command": "app:newTab",
@@ -125,39 +131,48 @@
},
{
"command": "app:selectWorkspace-1",
"keys": ["Cmd:Ctrl:1"]
"keys": ["Cmd:Ctrl:1"],
"commandStr": "/session 1"
},
{
"command": "app:selectWorkspace-2",
"keys": ["Cmd:Ctrl:2"]
"keys": ["Cmd:Ctrl:2"],
"commandStr": "/session 2"
},
{
"command": "app:selectWorkspace-3",
"keys": ["Cmd:Ctrl:3"]
"keys": ["Cmd:Ctrl:3"],
"commandStr": "/session 3"
},
{
"command": "app:selectWorkspace-4",
"keys": ["Cmd:Ctrl:4"]
"keys": ["Cmd:Ctrl:4"],
"commandStr": "/session 4"
},
{
"command": "app:selectWorkspace-5",
"keys": ["Cmd:Ctrl:5"]
"keys": ["Cmd:Ctrl:5"],
"commandStr": "/session 5"
},
{
"command": "app:selectWorkspace-6",
"keys": ["Cmd:Ctrl:6"]
"keys": ["Cmd:Ctrl:6"],
"commandStr": "/session 6"
},
{
"command": "app:selectWorkspace-7",
"keys": ["Cmd:Ctrl:7"]
"keys": ["Cmd:Ctrl:7"],
"commandStr": "/session 7"
},
{
"command": "app:selectWorkspace-8",
"keys": ["Cmd:Ctrl:8"]
"keys": ["Cmd:Ctrl:8"],
"commandStr": "/session 8"
},
{
"command": "app:selectWorkspace-9",
"keys": ["Cmd:Ctrl:9"]
"keys": ["Cmd:Ctrl:9"],
"commandStr": "/session 9"
},
{
"command": "app:toggleSidebar",
@@ -168,8 +183,9 @@
"keys": ["Cmd:d"]
},
{
"command": "app:bookmarkActiveLine",
"keys": ["Cmd:b"]
"command": "app:openBookmarksView",
"keys": ["Cmd:b"],
"commandStr": "/bookmarks:show"
},
{
"command": "bookmarks:edit",
@@ -213,7 +229,8 @@
},
{
"command": "cmdinput:openHistory",
"keys": ["Ctrl:r"]
"keys": ["Ctrl:r"],
"commandStr": "/history"
},
{
"command": "cmdinput:openAIChat",
Binary file not shown.
Binary file not shown.
+3 -2
View File
@@ -3,7 +3,7 @@
:root {
/*
* term colors (16 + 5) form the base terminal theme
* term colors (16 + 6) form the base terminal theme
* for consistency these colors should be used by plugins/applications
*/
--term-black: #000000;
@@ -27,5 +27,6 @@
--term-cmdtext: #ffffff;
--term-foreground: #d3d7cf;
--term-background: #000000;
--term-selection-background: #ffffff40;
--term-selection-background: #ffffff90;
--term-cursor-accent: #000000;
}
+2 -1
View File
@@ -6,5 +6,6 @@
--term-foreground: #000000;
--term-background: #fefefe;
--term-cmdtext: #000000;
--term-selection-background: #00000018;
--term-selection-background: #00000040;
--term-cursor-accent: #000000;
}
+1 -1
View File
@@ -193,7 +193,7 @@ class BookmarksView extends React.Component<{}, {}> {
let bookmarks = GlobalModel.bookmarksModel.bookmarks;
let bookmark: BookmarkType = null;
return (
<MainView viewName="bookmarks" title="Bookmarks" onClose={this.handleClose}>
<MainView className="bookmarks-view" title="Bookmarks" onClose={this.handleClose}>
<div className="bookmarks-list">
<For index="idx" each="bookmark" of={bookmarks}>
<Bookmark key={bookmark.bookmarkid} bookmark={bookmark} />
@@ -87,6 +87,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
const availableFontFamilies: DropdownItem[] = [];
availableFontFamilies.push({ label: "JetBrains Mono", value: "JetBrains Mono" });
availableFontFamilies.push({ label: "Hack", value: "Hack" });
availableFontFamilies.push({ label: "Fira Code", value: "Fira Code" });
return availableFontFamilies;
}
+1 -1
View File
@@ -44,7 +44,7 @@ class AlertModal extends React.Component<{}, {}> {
<Markdown text={message?.message ?? ""} extraClassName="bottom-margin" />
</If>
<If condition={!message?.markdown}>{message?.message}</If>
<If condition={message.confirmflag}>
<If condition={message?.confirmflag}>
<Checkbox
onChange={this.handleDontShowAgain}
label={"Don't show me this again"}
-276
View File
@@ -1,276 +0,0 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { debounce } from "throttle-debounce";
import * as util from "@/util/util";
import { GlobalModel } from "@/models";
class SimpleBlobRendererModel {
context: RendererContext;
opts: RendererOpts;
isDone: OV<boolean>;
api: RendererModelContainerApi;
savedHeight: number;
loading: OV<boolean>;
loadError: OV<string> = mobx.observable.box(null, {
name: "renderer-loadError",
});
lineState: LineStateType;
ptyData: PtyDataType;
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
dataBlob: Blob;
readOnly: boolean;
notFound: boolean;
initialize(params: RendererModelInitializeParams): void {
this.loading = mobx.observable.box(true, { name: "renderer-loading" });
this.isDone = mobx.observable.box(params.isDone, {
name: "renderer-isDone",
});
this.context = params.context;
this.opts = params.opts;
this.api = params.api;
this.lineState = params.lineState;
this.savedHeight = params.savedHeight;
this.ptyDataSource = params.ptyDataSource;
if (this.isDone.get()) {
setTimeout(() => this.reload(0), 10);
}
}
dispose(): void {
return;
}
giveFocus(): void {
return;
}
updateOpts(update: RendererOptsUpdate): void {
Object.assign(this.opts, update);
}
updateHeight(newHeight: number): void {
if (this.savedHeight != newHeight) {
this.savedHeight = newHeight;
this.api.saveHeight(newHeight);
}
}
setIsDone(): void {
if (this.isDone.get()) {
return;
}
mobx.action(() => {
this.isDone.set(true);
})();
this.reload(0);
}
reload(delayMs: number): void {
mobx.action(() => {
this.loading.set(true);
})();
if (delayMs == 0) {
this.reload_noDelay();
} else {
setTimeout(() => {
this.reload_noDelay();
}, delayMs);
}
}
reload_noDelay(): void {
let source = this.lineState["prompt:source"] || "pty";
if (source == "pty") {
this.reloadPtyData();
} else if (source == "file") {
this.reloadFileData();
} else {
mobx.action(() => {
this.loadError.set("error: invalid load source: " + source);
})();
}
}
reloadFileData(): void {
// todo add file methods to API, so we don't have a GlobalModel dependency here!
let path = this.lineState["prompt:file"];
if (util.isBlank(path)) {
mobx.action(() => {
this.loadError.set("renderer has file source, but no prompt:file specified");
})();
return;
}
let rtnp = GlobalModel.readRemoteFile(this.context.screenId, this.context.lineId, path);
rtnp.then((file) => {
this.notFound = (file as any).notFound;
this.readOnly = (file as any).readOnly;
this.dataBlob = file;
mobx.action(() => {
this.loading.set(false);
this.loadError.set(null);
})();
}).catch((e) => {
mobx.action(() => {
this.loadError.set("error loading file data: " + e);
})();
});
}
reloadPtyData(): void {
this.readOnly = true;
let rtnp = this.ptyDataSource(this.context);
if (rtnp == null) {
console.log("no promise returned from ptyDataSource (simplerenderer)", this.context);
return;
}
rtnp.then((ptydata) => {
this.ptyData = ptydata;
this.dataBlob = new Blob([this.ptyData.data]);
mobx.action(() => {
this.loading.set(false);
this.loadError.set(null);
})();
}).catch((e) => {
mobx.action(() => {
this.loadError.set("error loading data: " + e);
})();
});
}
receiveData(pos: number, data: Uint8Array, reason?: string): void {
// this.dataBuf.receiveData(pos, data, reason);
}
}
@mobxReact.observer
class SimpleBlobRenderer extends React.Component<
{
rendererContainer: RendererContainerType;
lineId: string;
plugin: RendererPluginType;
onHeightChange: () => void;
initParams: RendererModelInitializeParams;
scrollToBringIntoViewport: () => void;
isSelected: boolean;
shouldFocus: boolean;
},
{}
> {
model: SimpleBlobRendererModel;
wrapperDivRef: React.RefObject<any> = React.createRef();
rszObs: ResizeObserver;
updateHeight_debounced: (newHeight: number) => void;
constructor(props: any) {
super(props);
let { rendererContainer, lineId, plugin, initParams } = this.props;
this.model = new SimpleBlobRendererModel();
this.model.initialize(initParams);
rendererContainer.registerRenderer(lineId, this.model);
this.updateHeight_debounced = debounce(1000, this.updateHeight.bind(this));
}
updateHeight(newHeight: number): void {
this.model.updateHeight(newHeight);
}
handleResize(entries: ResizeObserverEntry[]): void {
if (this.model.loading.get()) {
return;
}
if (this.props.onHeightChange) {
this.props.onHeightChange();
}
if (!this.model.loading.get() && this.wrapperDivRef.current != null) {
let height = this.wrapperDivRef.current.offsetHeight;
this.updateHeight_debounced(height);
}
}
checkRszObs() {
if (this.rszObs != null) {
return;
}
if (this.wrapperDivRef.current == null) {
return;
}
this.rszObs = new ResizeObserver(this.handleResize.bind(this));
this.rszObs.observe(this.wrapperDivRef.current);
}
componentDidMount() {
this.checkRszObs();
}
componentWillUnmount() {
let { rendererContainer, lineId } = this.props;
rendererContainer.unloadRenderer(lineId);
if (this.rszObs != null) {
this.rszObs.disconnect();
this.rszObs = null;
}
}
componentDidUpdate() {
this.checkRszObs();
}
render() {
let { plugin } = this.props;
let model = this.model;
if (model.loadError.get() != null) {
let errorText = model.loadError.get();
let height = this.model.savedHeight;
return (
<div ref={this.wrapperDivRef} style={{ minHeight: height, fontSize: model.opts.termFontSize }}>
<div className="load-error-text">ERROR: {errorText}</div>
</div>
);
}
if (model.loading.get()) {
let height = this.model.savedHeight;
return (
<div
ref={this.wrapperDivRef}
className="renderer-loading"
style={{ minHeight: height, fontSize: model.opts.termFontSize }}
>
loading content <i className="fa fa-ellipsis fa-fade" />
</div>
);
}
let Comp = plugin.simpleComponent;
if (Comp == null) {
<div ref={this.wrapperDivRef}>(no component found in plugin)</div>;
}
let { festate, cmdstr, exitcode } = this.props.initParams.rawCmd;
return (
<div ref={this.wrapperDivRef} className="sr-wrapper">
<Comp
cwd={festate.cwd}
cmdstr={cmdstr}
exitcode={exitcode}
data={model.dataBlob as ExtBlob}
readOnly={model.readOnly}
notFound={model.notFound}
lineState={model.lineState}
context={model.context}
opts={model.opts}
savedHeight={model.savedHeight}
scrollToBringIntoViewport={this.props.scrollToBringIntoViewport}
isSelected={this.props.isSelected}
shouldFocus={this.props.shouldFocus}
rendererApi={model.api}
/>
</div>
);
}
}
export { SimpleBlobRendererModel, SimpleBlobRenderer };
+19 -2
View File
@@ -263,7 +263,12 @@ const menuTemplate: Electron.MenuItemConstructorOptions[] = [
{ type: "separator" },
{ role: "services" },
{ type: "separator" },
{ role: "hide" },
{
label: "Hide",
click: () => {
app.hide();
},
},
{ role: "hideOthers" },
{ type: "separator" },
{ role: "quit" },
@@ -303,16 +308,21 @@ function shFrameNavHandler(event: Electron.Event<Electron.WebContentsWillFrameNa
// only use this handler to process iframe events (non-iframe events go to shNavHandler)
return;
}
event.preventDefault();
const url = event.url;
console.log(`frame-navigation url=${url} frame=${event.frame.name}`);
if (event.frame.name == "webview") {
// "webview" links always open in new window
// this will *not* effect the initial load because srcdoc does not count as an electron navigation
console.log("open external, frameNav", url);
event.preventDefault();
electron.shell.openExternal(url);
return;
}
if (event.frame.name == "pdfview" && url.startsWith("blob:file:///")) {
// allowed
return;
}
event.preventDefault();
console.log("frame navigation canceled");
}
@@ -513,6 +523,13 @@ electron.ipcMain.on("toggle-developer-tools", (event) => {
event.returnValue = true;
});
electron.ipcMain.on("hide-window", (event) => {
if (MainWindow != null) {
MainWindow.hide();
}
event.returnValue = true;
});
electron.ipcMain.on("get-id", (event) => {
event.returnValue = instanceId + ":" + event.processId;
});
+1
View File
@@ -1,6 +1,7 @@
let { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("api", {
hideWindow: () => ipc.Renderer.send("hide-window"),
toggleDeveloperTools: () => ipcRenderer.send("toggle-developer-tools"),
getId: () => ipcRenderer.sendSync("get-id"),
getPlatform: () => ipcRenderer.sendSync("get-platform"),
+1 -1
View File
@@ -206,7 +206,7 @@ class BookmarksModel {
}
handleDocKeyDown(e: any): void {
let waveEvent = adaptFromReactOrNativeKeyEvent(e);
const waveEvent = adaptFromReactOrNativeKeyEvent(e);
if (checkKeyPressed(waveEvent, "Escape")) {
e.preventDefault();
if (this.editingBookmark.get() != null) {
+10
View File
@@ -3,6 +3,7 @@
import * as mobx from "mobx";
import { Model } from "./model";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
class ClientSettingsViewModel {
globalModel: Model;
@@ -21,6 +22,15 @@ class ClientSettingsViewModel {
this.globalModel.activeMainView.set("clientsettings");
})();
}
handleDocKeyDown(e: any): void {
const waveEvent = adaptFromReactOrNativeKeyEvent(e);
if (checkKeyPressed(waveEvent, "Escape")) {
e.preventDefault();
this.closeView();
return;
}
}
}
export { ClientSettingsViewModel };
+4
View File
@@ -304,6 +304,10 @@ class CommandRunner {
GlobalModel.clientSettingsViewModel.showClientSettingsView();
}
syncShellState() {
GlobalModel.submitCommand("sync", null, null, { nohist: "1" }, false);
}
historyView(params: HistorySearchParams) {
let kwargs = { nohist: "1" };
kwargs["offset"] = String(params.offset);
+10
View File
@@ -3,6 +3,7 @@
import * as mobx from "mobx";
import { Model } from "./model";
import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil";
class ConnectionsViewModel {
globalModel: Model;
@@ -21,6 +22,15 @@ class ConnectionsViewModel {
this.globalModel.activeMainView.set("connections");
})();
}
handleDocKeyDown(e: any): void {
const waveEvent = adaptFromReactOrNativeKeyEvent(e);
if (checkKeyPressed(waveEvent, "Escape")) {
e.preventDefault();
this.closeView();
return;
}
}
}
export { ConnectionsViewModel };
+1 -1
View File
@@ -291,7 +291,7 @@ class HistoryViewModel {
}
handleDocKeyDown(e: any): void {
let waveEvent = adaptFromReactOrNativeKeyEvent(e);
const waveEvent = adaptFromReactOrNativeKeyEvent(e);
if (checkKeyPressed(waveEvent, "Escape")) {
e.preventDefault();
this.closeView();
+2 -1
View File
@@ -18,10 +18,11 @@ class ModalsModel {
}
}
popModal() {
popModal(callback?: () => void) {
mobx.action(() => {
this.store.pop();
})();
callback && callback();
}
}
+31 -61
View File
@@ -143,7 +143,7 @@ class Model {
this.runUpdate(message, interactive);
});
this.ws.reconnect();
this.keybindManager = new KeybindManager();
this.keybindManager = new KeybindManager(this);
this.readConfigKeybindings();
this.initSystemKeybindings();
this.initAppKeybindings();
@@ -222,46 +222,31 @@ class Model {
getApi().toggleDeveloperTools();
return true;
});
this.keybindManager.registerKeybinding("system", "electron", "system:minimizeWindow", (waveEvent) => {
getApi().hideWindow();
return true;
});
}
initAppKeybindings() {
for (let index = 1; index <= 9; index++) {
this.keybindManager.registerKeybinding("app", "model", "app:selectWorkspace-" + index, (waveEvent) => {
this.onSwitchSessionCmd(index);
return true;
});
this.keybindManager.registerKeybinding("app", "model", "app:selectWorkspace-" + index, null);
}
this.keybindManager.registerKeybinding("app", "model", "app:focusCmdInput", (waveEvent) => {
console.log("focus cmd input callback");
this.onFocusCmdInputPressed();
return true;
});
this.keybindManager.registerKeybinding("app", "model", "app:bookmarkActiveLine", (waveEvent) => {
this.onBookmarkViewPressed();
return true;
});
this.keybindManager.registerKeybinding("app", "model", "app:openHistory", (waveEvent) => {
this.keybindManager.registerKeybinding("app", "model", "app:openBookmarksView", null);
this.keybindManager.registerKeybinding("app", "model", "app:openHistoryView", (waveEvent) => {
this.onOpenHistoryPressed();
return true;
});
this.keybindManager.registerKeybinding("app", "model", "app:openTabSearchModal", (waveEvent) => {
this.onOpenTabSearchModalPressed();
return true;
});
this.keybindManager.registerKeybinding("app", "model", "app:openConnectionsView", (waveEvent) => {
this.onOpenConnectionsViewPressed();
return true;
});
this.keybindManager.registerKeybinding("app", "model", "app:openSettingsView", (waveEvent) => {
this.onOpenSettingsViewPressed();
return true;
});
this.keybindManager.registerKeybinding("app", "model", "app:openConnectionsView", null);
this.keybindManager.registerKeybinding("app", "model", "app:openSettingsView", null);
}
static getInstance(): Model {
@@ -372,7 +357,6 @@ class Model {
cancelAlert(): void {
mobx.action(() => {
this.alertMessage.set(null);
this.modalsModel.popModal();
})();
if (this.alertPromiseResolver != null) {
this.alertPromiseResolver(false);
@@ -493,7 +477,7 @@ class Model {
if (this.alertMessage.get() != null) {
if (checkKeyPressed(waveEvent, "Escape")) {
e.preventDefault();
this.cancelAlert();
this.modalsModel.popModal(() => this.cancelAlert());
return;
}
if (checkKeyPressed(waveEvent, "Enter")) {
@@ -503,6 +487,10 @@ class Model {
}
return;
}
if (checkKeyPressed(waveEvent, "Escape") && this.modalsModel.store.length > 0) {
this.modalsModel.popModal();
return;
}
if (this.activeMainView.get() == "bookmarks") {
this.bookmarksModel.handleDocKeyDown(e);
}
@@ -510,10 +498,10 @@ class Model {
this.historyViewModel.handleDocKeyDown(e);
}
if (this.activeMainView.get() == "connections") {
this.historyViewModel.handleDocKeyDown(e);
this.connectionViewModel.handleDocKeyDown(e);
}
if (this.activeMainView.get() == "clientsettings") {
this.historyViewModel.handleDocKeyDown(e);
this.clientSettingsViewModel.handleDocKeyDown(e);
} else {
if (checkKeyPressed(waveEvent, "Escape")) {
e.preventDefault();
@@ -521,9 +509,6 @@ class Model {
this.showSessionView();
return;
}
if (this.clearModals()) {
return;
}
const inputModel = this.inputModel;
inputModel.toggleInfoMsg();
if (inputModel.inputMode.get() != null) {
@@ -643,33 +628,6 @@ class Model {
return screen.getTermWrap(line.lineid);
}
clearModals(): boolean {
let didSomething = false;
mobx.action(() => {
if (this.screenSettingsModal.get()) {
this.screenSettingsModal.set(null);
didSomething = true;
}
if (this.sessionSettingsModal.get()) {
this.sessionSettingsModal.set(null);
didSomething = true;
}
if (this.screenSettingsModal.get()) {
this.screenSettingsModal.set(null);
didSomething = true;
}
if (this.clientSettingsModal.get()) {
this.clientSettingsModal.set(false);
didSomething = true;
}
if (this.lineSettingsModal.get()) {
this.lineSettingsModal.set(null);
didSomething = true;
}
})();
return didSomething;
}
restartWaveSrv(): void {
getApi().restartWaveSrv();
}
@@ -1023,6 +981,12 @@ class Model {
console.warn("invalid bookmarksview in update:", update.mainview);
}
break;
case "clientsettings":
this.activeMainView.set("clientsettings");
break;
case "connections":
this.activeMainView.set("connections");
break;
case "plugins":
this.pluginsModel.showPluginsView();
break;
@@ -1086,6 +1050,9 @@ class Model {
this.activeMainView.set("session");
this.deactivateScreenLines();
this.ws.watchScreen(newActiveSessionId, newActiveScreenId);
setTimeout(() => {
GlobalCommandRunner.syncShellState();
}, 100);
}
} else {
console.warn("unknown update", genUpdate);
@@ -1583,12 +1550,15 @@ class Model {
return remote.remotecanonicalname;
}
readRemoteFile(screenId: string, lineId: string, path: string): Promise<ExtFile> {
const urlParams = {
readRemoteFile(screenId: string, lineId: string, path: string, mimetype?: string): Promise<ExtFile> {
const urlParams: Record<string, string> = {
screenid: screenId,
lineid: lineId,
path: path,
};
if (mimetype != null) {
urlParams["mimetype"] = mimetype;
}
const usp = new URLSearchParams(urlParams);
const url = new URL(this.getBaseHostPort() + "/api/read-file?" + usp.toString());
const fetchHeaders = this.getFetchHeaders();
+6
View File
@@ -1,4 +1,10 @@
.image-renderer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding-top: var(--termpad);
img {
display: block;
}
+7
View File
@@ -0,0 +1,7 @@
.pdf-renderer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding-top: var(--termpad);
}

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