diff --git a/src/app/app.less b/src/app/app.less index 9d9e84643..d7429b8dc 100644 --- a/src/app/app.less +++ b/src/app/app.less @@ -664,3 +664,161 @@ a.a-block { } } } + +.settings-field { + display: flex; + flex-direction: row; + align-items: center; + + &.settings-field.sub-field { + .settings-label { + font-weight: normal; + + text-align: right; + padding-right: 20px; + } + } + + &.settings-error { + color: @term-red; + margin-top: 20px; + padding: 10px; + border-radius: 5px; + background-color: #200707; + border: 1px solid @term-red; + font-weight: bold; + + .error-dismiss { + padding: 2px; + cursor: pointer; + } + } + + .settings-label { + font-weight: bold; + width: 12em; + display: flex; + flex-direction: row; + align-items: center; + .info-message { + margin-left: 5px; + } + } + + .settings-input { + display: flex; + flex-direction: row; + align-items: center; + color: @term-white; + + &.settings-clickable { + cursor: pointer; + } + + &.inline-edit.edit-active { + input.input { + padding: 0; + height: 20px; + } + + .button { + height: 20px; + } + } + + input { + padding: 4px; + border-radius: 3px; + } + + .control { + .icon { + width: 1.5em; + height: 1.5em; + margin: 0; + } + } + + .tab-color-icon.color-default path { + fill: @tab-green; + } + .tab-color-icon.color-green path { + fill: @tab-green; + } + .tab-color-icon.color-orange path { + fill: @tab-orange; + } + .tab-color-icon.color-red path { + fill: @tab-red; + } + .tab-color-icon.color-yellow path { + fill: @tab-yellow; + } + .tab-color-icon.color-blue path { + fill: @tab-blue; + } + .tab-color-icon.color-mint path { + fill: @tab-mint; + } + .tab-color-icon.color-cyan path { + fill: @tab-cyan; + } + .tab-color-icon.color-white path { + fill: @tab-white; + } + .tab-color-icon.color-violet path { + fill: @tab-violet; + } + .tab-color-icon.color-pink path { + fill: @tab-pink; + } + + .tab-colors, + .tab-icons { + display: flex; + flex-direction: row; + align-items: center; + + .tab-color-sep, + .tab-icon-sep { + padding-left: 10px; + padding-right: 10px; + font-weight: bold; + } + + .tab-color-icon, + .tab-icon-icon { + width: 1.1em; + vertical-align: middle; + } + + .tab-color-name, + .tab-icon-name { + margin-left: 1em; + } + + .tab-color-select, + .tab-icon-select { + cursor: pointer; + margin: 5px; + &:hover { + outline: 2px solid white; + } + } + } + + .action-text { + margin-left: 20px; + + color: @term-red; + } + + .settings-share-link { + width: 160px; + } + } + + &:not(:first-child) { + margin-top: 10px; + } +} diff --git a/src/app/common/modals/index.tsx b/src/app/common/modals/index.tsx index 50da27888..a95fc732f 100644 --- a/src/app/common/modals/index.tsx +++ b/src/app/common/modals/index.tsx @@ -6,3 +6,6 @@ export { CreateRemoteConnModal } from "./createremoteconn"; export { ViewRemoteConnDetailModal } from "./viewremoteconndetail"; export { EditRemoteConnModal } from "./editremoteconn"; export { TabSwitcherModal } from "./tabswitcher"; +export { SessionSettingsModal } from "./sessionsettings"; +export { ScreenSettingsModal } from "./screensettings"; +export { LineSettingsModal } from "./linesettings"; diff --git a/src/app/common/modals/linesettings.less b/src/app/common/modals/linesettings.less new file mode 100644 index 000000000..d7f2c03b0 --- /dev/null +++ b/src/app/common/modals/linesettings.less @@ -0,0 +1,23 @@ +@import "../../../app/common/themes/themes.less"; + +.line-settings-modal { + width: 640px; + + .wave-modal-content { + gap: 24px; + + .wave-modal-body { + display: flex; + padding: 0px 20px; + flex-direction: column; + align-items: flex-start; + gap: 4px; + align-self: stretch; + width: 100%; + + .settings-input .hotkey { + color: @text-secondary; + } + } + } +} diff --git a/src/app/common/modals/linesettings.tsx b/src/app/common/modals/linesettings.tsx new file mode 100644 index 000000000..b7c3d7dda --- /dev/null +++ b/src/app/common/modals/linesettings.tsx @@ -0,0 +1,151 @@ +// 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 { boundMethod } from "autobind-decorator"; +import { GlobalModel, GlobalCommandRunner } from "../../../model/model"; +import { SettingsError, Modal, Dropdown } from "../common"; +import { LineType, RendererPluginType } from "../../../types/types"; +import { PluginModel } from "../../../plugins/plugins"; +import { commandRtnHandler } from "../../../util/util"; + +import "./linesettings.less"; + +type OV = mobx.IObservableValue; + +@mobxReact.observer +class LineSettingsModal extends React.Component<{}, {}> { + rendererDropdownActive: OV = mobx.observable.box(false, { name: "lineSettings-rendererDropdownActive" }); + errorMessage: OV = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" }); + linenum: number; + + constructor(props: any) { + super(props); + this.linenum = GlobalModel.lineSettingsModal.get(); + if (this.linenum == null) { + return; + } + } + + @boundMethod + closeModal(): void { + mobx.action(() => { + GlobalModel.lineSettingsModal.set(null); + })(); + GlobalModel.modalsModel.popModal(); + } + + @boundMethod + handleChangeArchived(val: boolean): void { + let line = this.getLine(); + if (line == null) { + return; + } + let prtn = GlobalCommandRunner.lineArchive(line.lineid, val); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + toggleRendererDropdown(): void { + mobx.action(() => { + this.rendererDropdownActive.set(!this.rendererDropdownActive.get()); + })(); + } + + getLine(): LineType { + let screen = GlobalModel.getActiveScreen(); + if (screen == null) { + return; + } + return screen.getLineByNum(this.linenum); + } + + @boundMethod + clickSetRenderer(renderer: string): void { + let line = this.getLine(); + if (line == null) { + return; + } + let prtn = GlobalCommandRunner.lineSet(line.lineid, { renderer: renderer }); + commandRtnHandler(prtn, this.errorMessage); + mobx.action(() => { + this.rendererDropdownActive.set(false); + })(); + } + + getOptions(plugins: RendererPluginType[]) { + // Add label and value to each object in the array + const options = plugins.map((item) => ({ + ...item, + label: item.name, + value: item.name, + })); + + // Create an additional object with label "terminal" and value null + const terminalItem = { + label: "terminal", + value: null, + name: null, + rendererType: null, + heightType: null, + dataType: null, + collapseType: null, + globalCss: null, + mimeTypes: null, + }; + + // Create an additional object with label "none" and value none + const noneItem = { + label: "none", + value: "none", + name: null, + rendererType: null, + heightType: null, + dataType: null, + collapseType: null, + globalCss: null, + mimeTypes: null, + }; + + // Combine the options with the terminal item + return [terminalItem, ...options, noneItem]; + } + + render() { + let line = this.getLine(); + if (line == null) { + setTimeout(() => { + this.closeModal(); + }, 0); + return null; + } + let plugins = PluginModel.rendererPlugins; + let renderer = line.renderer ?? "terminal"; + + return ( + + +
+
+
Renderer
+
+ +
+
+ +
+
+ + + ); + } +} + +export { LineSettingsModal }; diff --git a/src/app/common/modals/registry.tsx b/src/app/common/modals/registry.tsx index 7b01e740b..42d738bd1 100644 --- a/src/app/common/modals/registry.tsx +++ b/src/app/common/modals/registry.tsx @@ -9,8 +9,10 @@ import { ViewRemoteConnDetailModal, EditRemoteConnModal, TabSwitcherModal, + SessionSettingsModal, + ScreenSettingsModal, + LineSettingsModal, } from "../modals"; -import { ScreenSettingsModal, SessionSettingsModal, LineSettingsModal } from "./settings"; import * as constants from "../../appconst"; const modalsRegistry: { [key: string]: () => React.ReactElement } = { diff --git a/src/app/common/modals/screensettings.less b/src/app/common/modals/screensettings.less new file mode 100644 index 000000000..5d2d7674d --- /dev/null +++ b/src/app/common/modals/screensettings.less @@ -0,0 +1,52 @@ +@import "../../../app/common/themes/themes.less"; + +.screen-settings-modal { + width: 640px; + + .wave-modal-content { + gap: 24px; + + .wave-modal-body { + display: flex; + padding: 0px 20px; + flex-direction: column; + align-items: flex-start; + gap: 4px; + align-self: stretch; + width: 100%; + + .screen-settings-dropdown { + width: 412px; + + .lefticon { + position: absolute; + top: 50%; + left: 16px; + transform: translateY(-50%); + + .globe-icon { + width: 16px; + height: 16px; + flex-shrink: 0; + } + + .status-icon { + position: absolute; + left: 7px; + top: 8px; + } + } + } + + .archived-label, + .actions-label { + div:first-child { + margin-right: 5px; + } + div:last-child i { + font-size: 13px; + } + } + } + } +} diff --git a/src/app/common/modals/screensettings.tsx b/src/app/common/modals/screensettings.tsx new file mode 100644 index 000000000..2034ca575 --- /dev/null +++ b/src/app/common/modals/screensettings.tsx @@ -0,0 +1,365 @@ +// 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 { boundMethod } from "autobind-decorator"; +import { If, For } from "tsx-control-statements/components"; +import cn from "classnames"; +import { GlobalModel, GlobalCommandRunner, TabColors, TabIcons, Screen } from "../../../model/model"; +import { Toggle, InlineSettingsTextEdit, SettingsError, Modal, Dropdown, Tooltip } from "../common"; +import { RemoteType } from "../../../types/types"; +import * as util from "../../../util/util"; +import { commandRtnHandler } from "../../../util/util"; +import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg"; +import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg"; +import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg"; + +import "./screensettings.less"; + +type OV = mobx.IObservableValue; + +const ScreenDeleteMessage = ` +Are you sure you want to delete this tab? + +All commands and output will be deleted. To hide the tab, and retain the commands and output, use 'archive'. +`.trim(); + +const WebShareConfirmMarkdown = ` +You are about to share a terminal tab on the web. Please make sure that you do +NOT share any private information, keys, passwords, or other sensitive information. +You are responsible for what you are sharing, be smart. +`.trim(); + +const WebStopShareConfirmMarkdown = ` +Are you sure you want to stop web-sharing this tab? +`.trim(); + +@mobxReact.observer +class ScreenSettingsModal extends React.Component<{}, {}> { + shareCopied: OV = mobx.observable.box(false, { name: "ScreenSettings-shareCopied" }); + errorMessage: OV = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" }); + screen: Screen; + sessionId: string; + screenId: string; + remotes: RemoteType[]; + + constructor(props) { + super(props); + let screenSettingsModal = GlobalModel.screenSettingsModal.get(); + let { sessionId, screenId } = screenSettingsModal; + this.sessionId = sessionId; + this.screenId = screenId; + this.screen = GlobalModel.getScreenById(sessionId, screenId); + if (this.screen == null || sessionId == null || screenId == null) { + return; + } + this.remotes = GlobalModel.remotes; + } + + @boundMethod + getOptions(): { label: string; value: string }[] { + return this.remotes + .filter((r) => !r.archived) + .map((remote) => ({ + ...remote, + label: + remote.remotealias && !util.isBlank(remote.remotealias) + ? `${remote.remotecanonicalname}` + : remote.remotecanonicalname, + value: remote.remotecanonicalname, + })) + .sort((a, b) => { + let connValA = util.getRemoteConnVal(a); + let connValB = util.getRemoteConnVal(b); + if (connValA !== connValB) { + return connValA - connValB; + } + return a.remoteidx - b.remoteidx; + }); + } + + @boundMethod + closeModal(): void { + mobx.action(() => { + GlobalModel.screenSettingsModal.set(null); + })(); + GlobalModel.modalsModel.popModal(); + } + + @boundMethod + selectTabColor(color: string): void { + if (this.screen == null) { + return; + } + if (this.screen.getTabColor() == color) { + return; + } + let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { tabcolor: color }, false); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + selectTabIcon(icon: string): void { + if (this.screen.getTabIcon() == icon) { + return; + } + let prtn = GlobalCommandRunner.screenSetSettings(this.screen.screenId, { tabicon: icon }, false); + util.commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + handleChangeArchived(val: boolean): void { + if (this.screen == null) { + return; + } + if (this.screen.archived.get() == val) { + return; + } + let prtn = GlobalCommandRunner.screenArchive(this.screenId, val); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + handleChangeWebShare(val: boolean): void { + if (this.screen == null) { + return; + } + if (this.screen.isWebShared() == val) { + return; + } + let message = val ? WebShareConfirmMarkdown : WebStopShareConfirmMarkdown; + let alertRtn = GlobalModel.showAlert({ message: message, confirm: true, markdown: true }); + alertRtn.then((result) => { + if (!result) { + return; + } + let prtn = GlobalCommandRunner.screenWebShare(this.screen.screenId, val); + commandRtnHandler(prtn, this.errorMessage); + }); + } + + @boundMethod + copyShareLink(): void { + if (this.screen == null) { + return null; + } + let shareLink = this.screen.getWebShareUrl(); + if (shareLink == null) { + return; + } + navigator.clipboard.writeText(shareLink); + mobx.action(() => { + this.shareCopied.set(true); + })(); + setTimeout(() => { + mobx.action(() => { + this.shareCopied.set(false); + })(); + }, 600); + } + + @boundMethod + inlineUpdateName(val: string): void { + if (this.screen == null) { + return; + } + if (util.isStrEq(val, this.screen.name.get())) { + return; + } + let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { name: val }, false); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + inlineUpdateShareName(val: string): void { + if (this.screen == null) { + return; + } + if (util.isStrEq(val, this.screen.getShareName())) { + return; + } + let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { sharename: val }, false); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + dismissError(): void { + mobx.action(() => { + this.errorMessage.set(null); + })(); + } + + @boundMethod + handleDeleteScreen(): void { + if (this.screen == null) { + return; + } + if (this.screen.getScreenLines().lines.length == 0) { + GlobalCommandRunner.screenDelete(this.screenId, false); + GlobalModel.modalsModel.popModal(); + return; + } + let message = ScreenDeleteMessage; + let alertRtn = GlobalModel.showAlert({ message: message, confirm: true, markdown: true }); + alertRtn.then((result) => { + if (!result) { + return; + } + let prtn = GlobalCommandRunner.screenDelete(this.screenId, false); + commandRtnHandler(prtn, this.errorMessage); + GlobalModel.modalsModel.popModal(); + }); + } + + @boundMethod + selectRemote(cname: string): void { + let prtn = GlobalCommandRunner.screenSetRemote(cname, true, false); + util.commandRtnHandler(prtn, this.errorMessage); + } + + render() { + let screen = this.screen; + if (screen == null) { + return null; + } + let color: string = null; + let icon: string = null; + let index: number = 0; + let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid); + + return ( + + +
+
+
Tab Id
+
{screen.screenId}
+
+
+
Name
+
+ +
+
+
+
Connection
+
+ + + +
+ ), + }} + /> +
+
+
+
Tab Color
+
+
+
+ + {screen.getTabColor()} +
+
|
+ +
this.selectTabColor(color)} + > + +
+
+
+
+
+
+
Tab Icon
+
+
+
+ + + + + + + {screen.getTabIcon()} +
+
|
+ +
this.selectTabIcon(icon)} + > + +
+
+
+
+
+
+
+
Archived
+ } + className="screen-settings-tooltip" + > + + +
+
+ +
+
+
+
+
Actions
+ } + className="screen-settings-tooltip" + > + + +
+
+
+ Delete Tab +
+
+
+ +
+ +
+ ); + } +} + +export { ScreenSettingsModal }; diff --git a/src/app/common/modals/sessionsettings.less b/src/app/common/modals/sessionsettings.less new file mode 100644 index 000000000..67e7a7e48 --- /dev/null +++ b/src/app/common/modals/sessionsettings.less @@ -0,0 +1,19 @@ +@import "../../../app/common/themes/themes.less"; + +.session-settings-modal { + width: 640px; + + .wave-modal-content { + gap: 24px; + + .wave-modal-body { + display: flex; + padding: 0px 20px; + flex-direction: column; + align-items: flex-start; + gap: 4px; + align-self: stretch; + width: 100%; + } + } +} diff --git a/src/app/common/modals/sessionsettings.tsx b/src/app/common/modals/sessionsettings.tsx new file mode 100644 index 000000000..f3ed4604f --- /dev/null +++ b/src/app/common/modals/sessionsettings.tsx @@ -0,0 +1,147 @@ +// 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 { boundMethod } from "autobind-decorator"; +import { GlobalModel, GlobalCommandRunner, Session } from "../../../model/model"; +import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage, Modal } from "../common"; +import * as util from "../../../util/util"; +import { commandRtnHandler } from "../../../util/util"; + +import "./sessionsettings.less"; + +type OV = mobx.IObservableValue; + +const SessionDeleteMessage = ` +Are you sure you want to delete this workspace? + +All commands and output will be deleted. To hide the workspace, and retain the commands and output, use 'archive'. +`.trim(); + +@mobxReact.observer +class SessionSettingsModal extends React.Component<{}, {}> { + errorMessage: OV = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" }); + session: Session; + sessionId: string; + + constructor(props: any) { + super(props); + this.sessionId = GlobalModel.sessionSettingsModal.get(); + this.session = GlobalModel.getSessionById(this.sessionId); + if (this.session == null) { + return; + } + } + + @boundMethod + closeModal(): void { + mobx.action(() => { + GlobalModel.sessionSettingsModal.set(null); + })(); + GlobalModel.modalsModel.popModal(); + } + + @boundMethod + handleInlineChangeName(newVal: string): void { + if (this.session == null) { + return; + } + if (util.isStrEq(newVal, this.session.name.get())) { + return; + } + let prtn = GlobalCommandRunner.sessionSetSettings(this.sessionId, { name: newVal }, false); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + handleChangeArchived(val: boolean): void { + if (this.session == null) { + return; + } + if (this.session.archived.get() == val) { + return; + } + let prtn = GlobalCommandRunner.sessionArchive(this.sessionId, val); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + handleDeleteSession(): void { + let message = SessionDeleteMessage; + let alertRtn = GlobalModel.showAlert({ message: message, confirm: true, markdown: true }); + alertRtn.then((result) => { + if (!result) { + return; + } + let prtn = GlobalCommandRunner.sessionDelete(this.sessionId); + commandRtnHandler(prtn, this.errorMessage, () => GlobalModel.modalsModel.popModal()); + }); + } + + @boundMethod + dismissError(): void { + mobx.action(() => { + this.errorMessage.set(null); + })(); + } + + render() { + if (this.session == null) { + return null; + } + return ( + + +
+
+
Name
+
+ +
+
+
+
+
Archived
+ + Archive will hide the workspace from the active menu. Commands and output will be + retained in history. + +
+
+ +
+
+
+
+
Actions
+ + Delete will remove the workspace, removing all commands and output from history. + +
+
+
+ Delete Workspace +
+
+
+ +
+ +
+ ); + } +} + +export { SessionSettingsModal }; diff --git a/src/app/common/modals/settings.less b/src/app/common/modals/settings.less deleted file mode 100644 index 7bd32d415..000000000 --- a/src/app/common/modals/settings.less +++ /dev/null @@ -1,1028 +0,0 @@ -@import "../../../app/common/themes/themes.less"; - -// modal css (also includes settings-field) - -.modal { - z-index: 105; - - .modal-background { - background-color: @base-background-transparent; - } -} - -.tos-modal { - a:hover { - text-decoration: underline; - } -} - -.disconnected-modal { - .wave-modal-content { - .wave-modal-body { - padding: 0; - - .modal-content { - footer { - .footer-text-link { - color: @term-white; - cursor: pointer; - } - } - } - - .inner-content { - .log { - height: 335px; - margin-bottom: 20px; - overflow: auto; - - &::-webkit-scrollbar-track, - &::-webkit-scrollbar-thumb, - &::-webkit-scrollbar-corner { - display: none; - } - - &:hover::-webkit-scrollbar-thumb { - display: block; - } - - pre { - color: @term-white; - background-color: @term-black; - } - } - } - } - - .wave-modal-footer { - button:first-child { - color: @term-green; - } - } - } -} - -.modal.prompt-modal.client-stop-modal { - footer { - justify-content: center; - } - - .inner-content { - display: flex; - flex-direction: column; - padding: 20px; - .progress-container { - margin-top: 20px; - } - .progress-text { - color: @term-white; - align-self: center; - } - } -} - -.modal.settings-modal { - footer { - justify-content: center; - - .button { - margin-left: 20px; - } - - .button:first-child { - margin-left: 0; - } - } - - .dropdown { - .dropdown-menu .dropdown-content { - .dropdown-item { - color: @term-white; - cursor: pointer; - &:hover { - background-color: #333; - } - } - } - - .dropdown-menu { - max-height: 120px; - overflow: auto; - } - } -} - -.modal.prompt-modal { - .modal-content { - border-radius: 5px; - background: @base-background; - box-shadow: 0px 2px 2px 0 rgba(255, 255, 255, 0.1), 0px 4px 5px 0 rgba(255, 255, 255, 0.2), - 0px 0px 5px 2.5px rgba(255, 255, 255, 0.5); - padding-bottom: 0.5em; - } - - header { - display: flex; - flex-direction: row; - padding: 10px; - position: relative; - background-color: @background-session-components-solid; - - .modal-title { - color: @base-color; - font-size: 1.5em; - .icon { - display: inline; - width: 1em; - height: 1em; - margin-right: 1em; - vertical-align: middle; - } - } - - .close-icon { - position: absolute; - right: 1em; - top: 0.8em; - cursor: pointer; - width: 1.5em; - height: 1.5em; - border-radius: 50%; - svg { - width: 1.5em; - height: 1.5em; - fill: @base-color; - } - } - } - - .inner-content { - padding: 1em; - margin: 0; - border-top: 1px solid fade(@base-border, 50%); - .icon { - display: inline; - width: 1em; - height: 1em; - } - &.is-hidden { - display: none; - } - .dropdown-trigger button { - justify-content: flex-start; - display: flex; - color: @base-color; - border: none !important; - &:hover { - box-shadow: none; - } - } - } - - footer { - display: flex; - flex-direction: row; - align-items: center; - padding: 15px 10px 10px 10px; - } -} - -.tos-modal { - width: 640px; - - .wave-modal-content .wave-modal-body { - padding: 32px 48px; - gap: 8px; - - .wave-modal-body-inner { - gap: 24px; - display: flex; - flex-direction: column; - - header.tos-header { - flex-direction: column; - gap: var(--sizing-sm, 12px); - border-bottom: none; - padding: 0; - - .modal-title { - text-align: center; - font-size: 20px; - font-weight: 300; - } - - .modal-subtitle { - color: @term-white; - text-align: center; - - font-style: normal; - font-weight: 300; - line-height: 20px; - } - } - - .content.tos-content { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 32px; - width: 100%; - margin-bottom: 0; - - .item { - display: flex; - width: 100%; - align-items: center; - gap: 16px; - - .item-inner { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 4px; - flex: 1 0 0; - - .item-title { - color: @term-bright-white; - font-style: normal; - line-height: 20px; - } - - .item-text { - color: @term-white; - font-style: normal; - line-height: 20px; - } - - .item-field { - display: flex; - align-items: center; - gap: 8px; - } - } - } - } - - footer { - .item-text { - text-align: center; - } - - .button-wrapper { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - - button { - font-size: 12.5px !important; - margin-top: 16px; - } - - button.disabled-button { - cursor: default; - } - } - } - } - } -} - -.about-modal { - .wave-modal-content { - gap: 24px; - - .wave-modal-body { - margin-bottom: 0; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 24px; - - .about-section { - display: flex; - align-items: center; - gap: 16px; - align-self: stretch; - width: 100%; - - .logo-wrapper { - width: 72px; - height: 72px; - flex-shrink: 0; - - img { - border-radius: 10px; - } - } - - .text-wrapper { - display: flex; - align-items: flex-start; - flex-direction: column; - gap: 4px; - align-self: stretch; - font-style: normal; - line-height: 20px; - - div:first-child { - color: @term-bright-white; - font-size: 14.5px; - } - - div:last-child { - color: @term-white; - text-align: left; - } - } - - .status { - div { - display: flex; - align-items: center; - margin-bottom: 5px; - - i { - font-size: 16px; - margin-right: 10px; - } - } - - div:first-child + div { - color: @term-white; - } - } - - .status.updated { - div { - display: flex; - align-items: center; - margin-bottom: 5px; - - i { - color: @term-green; - } - } - } - - .status.outdated { - div { - i { - color: @term-yellow; - } - } - - button { - margin-top: 5px; - } - } - } - - .about-section:nth-child(3) { - display: flex; - align-items: flex-start; - gap: 10px; - - .wave-button-link { - display: flex; - align-items: center; - - i { - font-size: 16px; - } - } - } - - .about-section:last-child { - margin-bottom: 24px; - color: @term-white; - } - } - } -} - -.crconn-modal { - width: 452px; - min-height: 411px; - - .wave-modal-content { - gap: 24px; - - .wave-modal-body { - display: flex; - padding: 0px 20px; - flex-direction: column; - align-items: flex-start; - gap: 12px; - align-self: stretch; - width: 100%; - - > div { - width: 100%; - } - } - } -} - -.screen-settings-modal { - width: 640px; - - .wave-modal-content { - gap: 24px; - - .wave-modal-body { - display: flex; - padding: 0px 20px; - flex-direction: column; - align-items: flex-start; - gap: 4px; - align-self: stretch; - width: 100%; - - .screen-settings-dropdown { - width: 412px; - - .lefticon { - position: absolute; - top: 50%; - left: 16px; - transform: translateY(-50%); - - .globe-icon { - width: 16px; - height: 16px; - flex-shrink: 0; - } - - .status-icon { - position: absolute; - left: 7px; - top: 8px; - } - } - } - - .archived-label, - .actions-label { - div:first-child { - margin-right: 5px; - } - div:last-child i { - font-size: 13px; - } - } - } - } -} - -.tabswitcher-modal { - width: 452px; - min-height: 384px; - - .wave-modal-content { - .wave-modal-body { - display: flex; - padding: 0px; - flex-direction: column; - align-items: flex-start; - align-self: stretch; - width: 100%; - - .textfield-wrapper { - padding: 20px 20px 0px; - - .wave-input-decoration.start-position { - height: 100%; - - .tabswitcher-search-prefix { - opacity: 0.5; - font-size: 13px; - } - } - } - - .list-container { - overflow: hidden; - padding: 10px 0 20px; - width: 100%; - } - - .list-container-inner { - width: 100%; - max-height: 300px; - overflow-y: scroll; - padding: 0 16px 0 20px; - - &::-webkit-scrollbar-thumb { - display: none; - } - - &:hover::-webkit-scrollbar-thumb { - display: block; - } - - .options-list { - width: 100%; - - .search-option { - padding: 5px 5px 5px 8px; - display: flex; - align-items: center; - border: 1px solid transparent; - width: 100%; - overflow: hidden; - - div.tabname { - flex-grow: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - padding-right: 5px; - } - - div.icon { - flex-shrink: 0; - width: 20px; - margin-right: 6px; - } - } - - .focused-option { - border: 1px solid rgba(241, 246, 243, 0.15); - border-radius: 4px; - background: rgba(255, 255, 255, 0.06); - } - } - } - } - } -} - -.screen-settings-tooltip .wave-tooltip-icon { - i { - font-size: 13px; - } -} - -.session-settings-modal { - width: 640px; - - .wave-modal-content { - gap: 24px; - - .wave-modal-body { - display: flex; - padding: 0px 20px; - flex-direction: column; - align-items: flex-start; - gap: 4px; - align-self: stretch; - width: 100%; - } - } -} - -.line-settings-modal { - width: 640px; - - .wave-modal-content { - gap: 24px; - - .wave-modal-body { - display: flex; - padding: 0px 20px; - flex-direction: column; - align-items: flex-start; - gap: 4px; - align-self: stretch; - width: 100%; - - .settings-input .hotkey { - color: @text-secondary; - } - } - } -} - -.client-settings-modal { - width: 640px; - - .wave-modal-content { - gap: 24px; - - .wave-modal-body { - display: flex; - padding: 0px 20px; - flex-direction: column; - align-items: flex-start; - gap: 4px; - align-self: stretch; - width: 100%; - } - } -} - -.erconn-modal { - width: 502px; - min-height: 411px; - - .wave-modal-content { - gap: 20px; - - .wave-modal-body { - display: flex; - padding: 0px 20px; - flex-direction: column; - align-items: flex-start; - gap: 12px; - align-self: stretch; - width: 100%; - - > div { - width: 100%; - } - - .name-actions-section { - margin-bottom: 10px; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 12px; - - .name { - color: @term-bright-white; - font-size: 15px; - font-weight: 500; - line-height: 20px; - } - - .header-actions { - display: flex; - justify-content: flex-end; - align-items: flex-start; - - .wave-button { - padding: 4px 15px; - font-size: 11px; - margin-right: 8px; - } - } - } - } - } -} - -.alert-modal { - width: 510px; - - .wave-modal-content { - .wave-modal-body { - padding: 40px 20px; - - .dontshowagain-text { - margin-top: 15px; - } - } - } -} - -.rconndetail-modal { - width: 631px; - min-height: 565px; - - .wave-modal-content { - display: flex; - padding-bottom: 0px; - flex-direction: column; - align-items: center; - gap: 20px; - flex-shrink: 0; - - .wave-modal-body { - display: flex; - padding: 0px 20px; - align-items: flex-start; - width: 100%; - display: flex; - flex-direction: column; - gap: 16px; - align-self: stretch; - - .name-header-actions-wrapper { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 12px; - - .name-wrapper { - display: flex; - flex-direction: row; - } - - .rconndetail-name { - color: @term-bright-white; - font-size: 15px; - font-weight: 500; - line-height: 20px; - } - - .header-actions { - display: flex; - justify-content: flex-end; - align-items: flex-start; - - .wave-button { - padding: 4px 15px; - font-size: 11px; - margin-right: 8px; - } - } - } - - .remote-detail { - .settings-field { - display: flex; - flex-direction: row; - align-items: center; - - .settings-label { - font-weight: bold; - width: 12em; - display: flex; - flex-direction: row; - align-items: center; - } - - .settings-input { - display: flex; - flex-direction: row; - align-items: center; - color: @term-white; - } - } - - .settings-field:not(:first-child) { - margin-top: 4px; - } - - .status { - display: flex; - height: 30px; - padding: 3px 8px; - align-items: center; - gap: 8px; - align-self: stretch; - border-radius: 6px; - background: rgba(241, 246, 243, 0.08); - } - - .terminal-wrapper { - width: 100%; - margin-top: 5px; - - .terminal-connectelem { - height: 163px !important; // Needed to override plugin height - - .xterm-viewport { - display: flex; - padding: 6px 10px; - gap: 8px; - align-items: flex-start; - align-self: stretch; - border-radius: 6px; - border: 1px solid var(--element-separator, rgba(241, 246, 243, 0.15)); - background: #080a08; - height: 163px !important; // Needed to override plugin height - } - - .xterm-screen { - padding: 10px; - width: 541px !important; // Needed to override plugin width - } - } - } - } - } - } -} - -.wave-button.color-standard { - color: @term-white; - background: rgba(255, 255, 255, 0.12); - - &:hover { - color: @term-white; - } -} - -.wave-button-link { - display: flex; - padding: 6px 16px; - align-items: center; - gap: var(--sizing-2-xs, 4px); - border-radius: 6px; - background: var(--overlays-white-6, rgba(255, 255, 255, 0.12)); - cursor: pointer; -} - -.wave-modal-section { - display: flex; - align-items: center; - gap: 16px; - align-self: stretch; - width: 100%; -} - -.modal.welcome-modal { - footer { - .prev-button { - margin-left: 15px; - width: 100px; - } - - .prev-spacer { - margin-left: 15px; - width: 100px; - } - - .next-button { - margin-right: 15px; - width: 100px; - } - - .dots { - i { - margin-left: 5px; - } - } - } -} - -.client-settings-modal { - .settings-field { - .settings-label { - width: 157px; - } - .dropdown-menu { - min-width: 7.25em; - max-width: 7.25em; - } - } -} - -.settings-field { - display: flex; - flex-direction: row; - align-items: center; - - &.settings-field.sub-field { - .settings-label { - font-weight: normal; - - text-align: right; - padding-right: 20px; - } - } - - &.settings-error { - color: @term-red; - margin-top: 20px; - padding: 10px; - border-radius: 5px; - background-color: #200707; - border: 1px solid @term-red; - font-weight: bold; - - .error-dismiss { - padding: 2px; - cursor: pointer; - } - } - - .settings-label { - font-weight: bold; - width: 12em; - display: flex; - flex-direction: row; - align-items: center; - .info-message { - margin-left: 5px; - } - } - - .settings-input { - display: flex; - flex-direction: row; - align-items: center; - - &.settings-clickable { - cursor: pointer; - } - - &.inline-edit.edit-active { - input.input { - padding: 0; - height: 20px; - } - - .button { - height: 20px; - } - } - - input { - padding: 4px; - border-radius: 3px; - } - - .control { - .icon { - width: 1.5em; - height: 1.5em; - margin: 0; - } - } - - .tab-color-icon.color-default path { - fill: @tab-green; - } - .tab-color-icon.color-green path { - fill: @tab-green; - } - .tab-color-icon.color-orange path { - fill: @tab-orange; - } - .tab-color-icon.color-red path { - fill: @tab-red; - } - .tab-color-icon.color-yellow path { - fill: @tab-yellow; - } - .tab-color-icon.color-blue path { - fill: @tab-blue; - } - .tab-color-icon.color-mint path { - fill: @tab-mint; - } - .tab-color-icon.color-cyan path { - fill: @tab-cyan; - } - .tab-color-icon.color-white path { - fill: @tab-white; - } - .tab-color-icon.color-violet path { - fill: @tab-violet; - } - .tab-color-icon.color-pink path { - fill: @tab-pink; - } - - .tab-colors, - .tab-icons { - display: flex; - flex-direction: row; - align-items: center; - - .tab-color-sep, - .tab-icon-sep { - padding-left: 10px; - padding-right: 10px; - font-weight: bold; - } - - .tab-color-icon, - .tab-icon-icon { - width: 1.1em; - vertical-align: middle; - } - - .tab-color-name, - .tab-icon-name { - margin-left: 1em; - } - - .tab-color-select, - .tab-icon-select { - cursor: pointer; - margin: 5px; - &:hover { - outline: 2px solid white; - } - } - } - - .action-text { - margin-left: 20px; - - color: @term-red; - } - - .settings-share-link { - width: 160px; - } - } - - &:not(:first-child) { - margin-top: 10px; - } -} diff --git a/src/app/common/modals/settings.tsx b/src/app/common/modals/settings.tsx deleted file mode 100644 index 7f61e2ab0..000000000 --- a/src/app/common/modals/settings.tsx +++ /dev/null @@ -1,838 +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 { boundMethod } from "autobind-decorator"; -import { If, For } from "tsx-control-statements/components"; -import cn from "classnames"; -import { - GlobalModel, - GlobalCommandRunner, - TabColors, - MinFontSize, - MaxFontSize, - TabIcons, - Screen, - Session, -} from "../../../model/model"; -import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage, Modal, Dropdown, Tooltip } from "../common"; -import { LineType, RendererPluginType, ClientDataType, CommandRtnType, RemoteType } from "../../../types/types"; -import { PluginModel } from "../../../plugins/plugins"; -import * as util from "../../../util/util"; -import { commandRtnHandler } from "../../../util/util"; -import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg"; -import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg"; -import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg"; - -import "./settings.less"; - -type OV = mobx.IObservableValue; - -// @ts-ignore -const VERSION = __WAVETERM_VERSION__; -// @ts-ignore -const BUILD = __WAVETERM_BUILD__; - -const ScreenDeleteMessage = ` -Are you sure you want to delete this tab? - -All commands and output will be deleted. To hide the tab, and retain the commands and output, use 'archive'. -`.trim(); - -const SessionDeleteMessage = ` -Are you sure you want to delete this workspace? - -All commands and output will be deleted. To hide the workspace, and retain the commands and output, use 'archive'. -`.trim(); - -const WebShareConfirmMarkdown = ` -You are about to share a terminal tab on the web. Please make sure that you do -NOT share any private information, keys, passwords, or other sensitive information. -You are responsible for what you are sharing, be smart. -`.trim(); - -const WebStopShareConfirmMarkdown = ` -Are you sure you want to stop web-sharing this tab? -`.trim(); - -@mobxReact.observer -class ScreenSettingsModal extends React.Component<{}, {}> { - shareCopied: OV = mobx.observable.box(false, { name: "ScreenSettings-shareCopied" }); - errorMessage: OV = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" }); - screen: Screen; - sessionId: string; - screenId: string; - remotes: RemoteType[]; - - constructor(props) { - super(props); - let screenSettingsModal = GlobalModel.screenSettingsModal.get(); - let { sessionId, screenId } = screenSettingsModal; - this.sessionId = sessionId; - this.screenId = screenId; - this.screen = GlobalModel.getScreenById(sessionId, screenId); - if (this.screen == null || sessionId == null || screenId == null) { - return; - } - this.remotes = GlobalModel.remotes; - } - - @boundMethod - getOptions(): { label: string; value: string }[] { - return this.remotes - .filter((r) => !r.archived) - .map((remote) => ({ - ...remote, - label: - remote.remotealias && !util.isBlank(remote.remotealias) - ? `${remote.remotecanonicalname}` - : remote.remotecanonicalname, - value: remote.remotecanonicalname, - })) - .sort((a, b) => { - let connValA = util.getRemoteConnVal(a); - let connValB = util.getRemoteConnVal(b); - if (connValA !== connValB) { - return connValA - connValB; - } - return a.remoteidx - b.remoteidx; - }); - } - - @boundMethod - closeModal(): void { - mobx.action(() => { - GlobalModel.screenSettingsModal.set(null); - })(); - GlobalModel.modalsModel.popModal(); - } - - @boundMethod - selectTabColor(color: string): void { - if (this.screen == null) { - return; - } - if (this.screen.getTabColor() == color) { - return; - } - let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { tabcolor: color }, false); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - selectTabIcon(icon: string): void { - if (this.screen.getTabIcon() == icon) { - return; - } - let prtn = GlobalCommandRunner.screenSetSettings(this.screen.screenId, { tabicon: icon }, false); - util.commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - handleChangeArchived(val: boolean): void { - if (this.screen == null) { - return; - } - if (this.screen.archived.get() == val) { - return; - } - let prtn = GlobalCommandRunner.screenArchive(this.screenId, val); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - handleChangeWebShare(val: boolean): void { - if (this.screen == null) { - return; - } - if (this.screen.isWebShared() == val) { - return; - } - let message = val ? WebShareConfirmMarkdown : WebStopShareConfirmMarkdown; - let alertRtn = GlobalModel.showAlert({ message: message, confirm: true, markdown: true }); - alertRtn.then((result) => { - if (!result) { - return; - } - let prtn = GlobalCommandRunner.screenWebShare(this.screen.screenId, val); - commandRtnHandler(prtn, this.errorMessage); - }); - } - - @boundMethod - copyShareLink(): void { - if (this.screen == null) { - return null; - } - let shareLink = this.screen.getWebShareUrl(); - if (shareLink == null) { - return; - } - navigator.clipboard.writeText(shareLink); - mobx.action(() => { - this.shareCopied.set(true); - })(); - setTimeout(() => { - mobx.action(() => { - this.shareCopied.set(false); - })(); - }, 600); - } - - @boundMethod - inlineUpdateName(val: string): void { - if (this.screen == null) { - return; - } - if (util.isStrEq(val, this.screen.name.get())) { - return; - } - let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { name: val }, false); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - inlineUpdateShareName(val: string): void { - if (this.screen == null) { - return; - } - if (util.isStrEq(val, this.screen.getShareName())) { - return; - } - let prtn = GlobalCommandRunner.screenSetSettings(this.screenId, { sharename: val }, false); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - dismissError(): void { - mobx.action(() => { - this.errorMessage.set(null); - })(); - } - - @boundMethod - handleDeleteScreen(): void { - if (this.screen == null) { - return; - } - if (this.screen.getScreenLines().lines.length == 0) { - GlobalCommandRunner.screenDelete(this.screenId, false); - GlobalModel.modalsModel.popModal(); - return; - } - let message = ScreenDeleteMessage; - let alertRtn = GlobalModel.showAlert({ message: message, confirm: true, markdown: true }); - alertRtn.then((result) => { - if (!result) { - return; - } - let prtn = GlobalCommandRunner.screenDelete(this.screenId, false); - commandRtnHandler(prtn, this.errorMessage); - GlobalModel.modalsModel.popModal(); - }); - } - - @boundMethod - selectRemote(cname: string): void { - let prtn = GlobalCommandRunner.screenSetRemote(cname, true, false); - util.commandRtnHandler(prtn, this.errorMessage); - } - - render() { - let screen = this.screen; - if (screen == null) { - return null; - } - let color: string = null; - let icon: string = null; - let index: number = 0; - let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid); - - return ( - - -
-
-
Tab Id
-
{screen.screenId}
-
-
-
Name
-
- -
-
-
-
Connection
-
- - - -
- ), - }} - /> -
-
-
-
Tab Color
-
-
-
- - {screen.getTabColor()} -
-
|
- -
this.selectTabColor(color)} - > - -
-
-
-
-
-
-
Tab Icon
-
-
-
- - - - - - - {screen.getTabIcon()} -
-
|
- -
this.selectTabIcon(icon)} - > - -
-
-
-
-
-
-
-
Archived
- } - className="screen-settings-tooltip" - > - - -
-
- -
-
-
-
-
Actions
- } - className="screen-settings-tooltip" - > - - -
-
-
- Delete Tab -
-
-
- - - -
- ); - } -} - -@mobxReact.observer -class SessionSettingsModal extends React.Component<{}, {}> { - errorMessage: OV = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" }); - session: Session; - sessionId: string; - - constructor(props: any) { - super(props); - this.sessionId = GlobalModel.sessionSettingsModal.get(); - this.session = GlobalModel.getSessionById(this.sessionId); - if (this.session == null) { - return; - } - } - - @boundMethod - closeModal(): void { - mobx.action(() => { - GlobalModel.sessionSettingsModal.set(null); - })(); - GlobalModel.modalsModel.popModal(); - } - - @boundMethod - handleInlineChangeName(newVal: string): void { - if (this.session == null) { - return; - } - if (util.isStrEq(newVal, this.session.name.get())) { - return; - } - let prtn = GlobalCommandRunner.sessionSetSettings(this.sessionId, { name: newVal }, false); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - handleChangeArchived(val: boolean): void { - if (this.session == null) { - return; - } - if (this.session.archived.get() == val) { - return; - } - let prtn = GlobalCommandRunner.sessionArchive(this.sessionId, val); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - handleDeleteSession(): void { - let message = SessionDeleteMessage; - let alertRtn = GlobalModel.showAlert({ message: message, confirm: true, markdown: true }); - alertRtn.then((result) => { - if (!result) { - return; - } - let prtn = GlobalCommandRunner.sessionDelete(this.sessionId); - commandRtnHandler(prtn, this.errorMessage, () => GlobalModel.modalsModel.popModal()); - }); - } - - @boundMethod - dismissError(): void { - mobx.action(() => { - this.errorMessage.set(null); - })(); - } - - render() { - if (this.session == null) { - return null; - } - return ( - - -
-
-
Name
-
- -
-
-
-
-
Archived
- - Archive will hide the workspace from the active menu. Commands and output will be - retained in history. - -
-
- -
-
-
-
-
Actions
- - Delete will remove the workspace, removing all commands and output from history. - -
-
-
- Delete Workspace -
-
-
- -
- -
- ); - } -} - -@mobxReact.observer -class LineSettingsModal extends React.Component<{}, {}> { - rendererDropdownActive: OV = mobx.observable.box(false, { name: "lineSettings-rendererDropdownActive" }); - errorMessage: OV = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" }); - linenum: number; - - constructor(props: any) { - super(props); - this.linenum = GlobalModel.lineSettingsModal.get(); - if (this.linenum == null) { - return; - } - } - - @boundMethod - closeModal(): void { - mobx.action(() => { - GlobalModel.lineSettingsModal.set(null); - })(); - GlobalModel.modalsModel.popModal(); - } - - @boundMethod - handleChangeArchived(val: boolean): void { - let line = this.getLine(); - if (line == null) { - return; - } - let prtn = GlobalCommandRunner.lineArchive(line.lineid, val); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - toggleRendererDropdown(): void { - mobx.action(() => { - this.rendererDropdownActive.set(!this.rendererDropdownActive.get()); - })(); - } - - getLine(): LineType { - let screen = GlobalModel.getActiveScreen(); - if (screen == null) { - return; - } - return screen.getLineByNum(this.linenum); - } - - @boundMethod - clickSetRenderer(renderer: string): void { - let line = this.getLine(); - if (line == null) { - return; - } - let prtn = GlobalCommandRunner.lineSet(line.lineid, { renderer: renderer }); - commandRtnHandler(prtn, this.errorMessage); - mobx.action(() => { - this.rendererDropdownActive.set(false); - })(); - } - - getOptions(plugins: RendererPluginType[]) { - // Add label and value to each object in the array - const options = plugins.map((item) => ({ - ...item, - label: item.name, - value: item.name, - })); - - // Create an additional object with label "terminal" and value null - const terminalItem = { - label: "terminal", - value: null, - name: null, - rendererType: null, - heightType: null, - dataType: null, - collapseType: null, - globalCss: null, - mimeTypes: null, - }; - - // Create an additional object with label "none" and value none - const noneItem = { - label: "none", - value: "none", - name: null, - rendererType: null, - heightType: null, - dataType: null, - collapseType: null, - globalCss: null, - mimeTypes: null, - }; - - // Combine the options with the terminal item - return [terminalItem, ...options, noneItem]; - } - - render() { - let line = this.getLine(); - if (line == null) { - setTimeout(() => { - this.closeModal(); - }, 0); - return null; - } - let plugins = PluginModel.rendererPlugins; - let renderer = line.renderer ?? "terminal"; - - return ( - - -
-
-
Renderer
-
- -
-
- -
-
- - - ); - } -} - -@mobxReact.observer -class ClientSettingsModal extends React.Component<{}, {}> { - fontSizeDropdownActive: OV = mobx.observable.box(false, { name: "clientSettings-fontSizeDropdownActive" }); - errorMessage: OV = mobx.observable.box(null, { name: "ClientSettings-errorMessage" }); - - @boundMethod - closeModal(): void { - GlobalModel.modalsModel.popModal(); - } - - @boundMethod - dismissError(): void { - mobx.action(() => { - this.errorMessage.set(null); - })(); - } - - @boundMethod - handleChangeFontSize(fontSize: string): void { - let newFontSize = Number(fontSize); - this.fontSizeDropdownActive.set(false); - if (GlobalModel.termFontSize.get() == newFontSize) { - return; - } - let prtn = GlobalCommandRunner.setTermFontSize(newFontSize, false); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - togglefontSizeDropdown(): void { - mobx.action(() => { - this.fontSizeDropdownActive.set(!this.fontSizeDropdownActive.get()); - })(); - } - - @boundMethod - handleChangeTelemetry(val: boolean): void { - let prtn: Promise = null; - if (val) { - prtn = GlobalCommandRunner.telemetryOn(false); - } else { - prtn = GlobalCommandRunner.telemetryOff(false); - } - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - handleChangeReleaseCheck(val: boolean): void { - let prtn: Promise = null; - if (val) { - prtn = GlobalCommandRunner.releaseCheckAutoOn(false); - } else { - prtn = GlobalCommandRunner.releaseCheckAutoOff(false); - } - commandRtnHandler(prtn, this.errorMessage); - } - - getFontSizes(): any { - let availableFontSizes: { label: string; value: number }[] = []; - for (let s = MinFontSize; s <= MaxFontSize; s++) { - availableFontSizes.push({ label: s + "px", value: s }); - } - return availableFontSizes; - } - - @boundMethod - inlineUpdateOpenAIModel(newModel: string): void { - let prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel }); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - inlineUpdateOpenAIToken(newToken: string): void { - let prtn = GlobalCommandRunner.setClientOpenAISettings({ apitoken: newToken }); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - inlineUpdateOpenAIMaxTokens(newMaxTokensStr: string): void { - let prtn = GlobalCommandRunner.setClientOpenAISettings({ maxtokens: newMaxTokensStr }); - commandRtnHandler(prtn, this.errorMessage); - } - - @boundMethod - setErrorMessage(msg: string): void { - mobx.action(() => { - this.errorMessage.set(msg); - })(); - } - - render() { - let cdata: ClientDataType = GlobalModel.clientData.get(); - let openAIOpts = cdata.openaiopts ?? {}; - let apiTokenStr = util.isBlank(openAIOpts.apitoken) ? "(not set)" : "********"; - let maxTokensStr = String( - openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens - ); - let curFontSize = GlobalModel.termFontSize.get(); - return ( - - -
-
-
Term Font Size
-
- -
-
-
-
Client ID
-
{cdata.clientid}
-
-
-
Client Version
-
- {VERSION} {BUILD} -
-
-
-
DB Version
-
{cdata.dbversion}
-
-
-
Basic Telemetry
-
- -
-
-
-
Check for Updates
-
- -
-
-
-
OpenAI Token
-
- -
-
-
-
OpenAI Model
-
- -
-
-
-
OpenAI MaxTokens
-
- -
-
- -
- -
- ); - } -} - -export { - ScreenSettingsModal, - SessionSettingsModal, - LineSettingsModal, - ClientSettingsModal, - WebStopShareConfirmMarkdown, -};