diff --git a/src/app/app.tsx b/src/app/app.tsx
index 42dba420..3acaa712 100644
--- a/src/app/app.tsx
+++ b/src/app/app.tsx
@@ -16,6 +16,7 @@ import { PluginsView } from "./pluginsview/pluginsview";
import { BookmarksView } from "./bookmarks/bookmarks";
import { HistoryView } from "./history/history";
import { ConnectionsView } from "./connections/connections";
+import { ClientSettingsView } from "./clientsettings/clientsettings";
import { MainSideBar } from "./sidebar/sidebar";
import { DisconnectedModal, ClientStopModal } from "./common/modals";
import { ModalsProvider } from "./common/modals/provider";
@@ -109,6 +110,7 @@ class App extends React.Component<{}, {}> {
+
diff --git a/src/app/clientsettings/clientsettings.less b/src/app/clientsettings/clientsettings.less
new file mode 100644
index 00000000..034953ec
--- /dev/null
+++ b/src/app/clientsettings/clientsettings.less
@@ -0,0 +1,200 @@
+@import "../../app/common/themes/themes.less";
+
+.clientsettings-view {
+ background-color: @background-session;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ overflow: auto;
+ margin-bottom: 10px;
+ margin-right: 10px;
+ border-radius: 8px;
+ border: 1px solid rgba(241, 246, 243, 0.08);
+ background: rgba(13, 13, 13, 0.85);
+
+ .header {
+ margin: 24px 18px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-bottom: 20px;
+ border-bottom: 1px solid white;
+ }
+
+ .content {
+ padding: 0 18px 0 30px;
+ }
+
+ // just marked these as important since we're keeping the
+ // settings-field styles below this intact until we figure out what do with them
+ .settings-field {
+ &:not(:first-child) {
+ margin-top: 15px !important;
+ }
+
+ .settings-label {
+ width: 250px !important;
+ }
+ }
+
+ // @TODO: These styles are duplicated in the settings modals
+ .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;
+ margin-right: 10px;
+
+ .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/clientsettings/clientsettings.tsx b/src/app/clientsettings/clientsettings.tsx
new file mode 100644
index 00000000..8d3c4cde
--- /dev/null
+++ b/src/app/clientsettings/clientsettings.tsx
@@ -0,0 +1,219 @@
+// 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 cn from "classnames";
+import { GlobalModel, GlobalCommandRunner, MinFontSize, MaxFontSize, RemotesModel } from "../../model/model";
+import { Toggle, InlineSettingsTextEdit, SettingsError, Dropdown } from "../common/common";
+import { CommandRtnType, ClientDataType } from "../../types/types";
+import { commandRtnHandler, isBlank } from "../../util/util";
+
+import "./clientsettings.less";
+
+type OV = mobx.IObservableValue;
+
+// @ts-ignore
+const VERSION = __WAVETERM_VERSION__;
+// @ts-ignore
+const BUILD = __WAVETERM_BUILD__;
+
+@mobxReact.observer
+class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
+ 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 isHidden = GlobalModel.activeMainView.get() != "clientsettings";
+ if (isHidden) {
+ return null;
+ }
+
+ let cdata: ClientDataType = GlobalModel.clientData.get();
+ let openAIOpts = cdata.openaiopts ?? {};
+ let apiTokenStr = isBlank(openAIOpts.apitoken) ? "(not set)" : "********";
+ let maxTokensStr = String(
+ openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens
+ );
+ let curFontSize = GlobalModel.termFontSize.get();
+
+ return (
+
+
+
+
+
+
Client ID
+
{cdata.clientid}
+
+
+
Client Version
+
+ {VERSION} {BUILD}
+
+
+
+
DB Version
+
{cdata.dbversion}
+
+
+
Basic Telemetry
+
+
+
+
+
+
Check for Updates
+
+
+
+
+
+
+
+
OpenAI MaxTokens
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export { ClientSettingsView };
diff --git a/src/app/common/modals/registry.tsx b/src/app/common/modals/registry.tsx
index ebdc8382..7b01e740 100644
--- a/src/app/common/modals/registry.tsx
+++ b/src/app/common/modals/registry.tsx
@@ -10,7 +10,7 @@ import {
EditRemoteConnModal,
TabSwitcherModal,
} from "../modals";
-import { ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSettingsModal } from "./settings";
+import { ScreenSettingsModal, SessionSettingsModal, LineSettingsModal } from "./settings";
import * as constants from "../../appconst";
const modalsRegistry: { [key: string]: () => React.ReactElement } = {
@@ -22,7 +22,6 @@ const modalsRegistry: { [key: string]: () => React.ReactElement } = {
[constants.SCREEN_SETTINGS]: () => ,
[constants.SESSION_SETTINGS]: () => ,
[constants.LINE_SETTINGS]: () => ,
- [constants.CLIENT_SETTINGS]: () => ,
[constants.TAB_SWITCHER]: () => ,
};
diff --git a/src/app/common/modals/settings.tsx b/src/app/common/modals/settings.tsx
index 3718a838..1ba089a2 100644
--- a/src/app/common/modals/settings.tsx
+++ b/src/app/common/modals/settings.tsx
@@ -17,22 +17,12 @@ import {
Screen,
Session,
} from "../../../model/model";
-import {
- Toggle,
- InlineSettingsTextEdit,
- SettingsError,
- InfoMessage,
- Modal,
- Dropdown,
- Tooltip,
- Button,
-} from "../common";
+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 AngleDownIcon } from "../../assets/icons/history/angle-down.svg";
import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg";
import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg";
diff --git a/src/app/sidebar/sidebar.tsx b/src/app/sidebar/sidebar.tsx
index 57dcd9bd..a0d1b64b 100644
--- a/src/app/sidebar/sidebar.tsx
+++ b/src/app/sidebar/sidebar.tsx
@@ -131,7 +131,11 @@ class MainSideBar extends React.Component<{}, {}> {
@boundMethod
handleSettingsClick(): void {
- GlobalModel.modalsModel.pushModal(constants.CLIENT_SETTINGS);
+ if (GlobalModel.activeMainView.get() == "clientsettings") {
+ GlobalModel.showSessionView();
+ return;
+ }
+ GlobalCommandRunner.clientSettingsView();
}
@boundMethod
diff --git a/src/model/model.ts b/src/model/model.ts
index 29b6487e..787a7dcc 100644
--- a/src/model/model.ts
+++ b/src/model/model.ts
@@ -2576,6 +2576,14 @@ class ConnectionsViewModel {
}
}
+class ClientSettingsViewModel {
+ showClientSettingsView(): void {
+ mobx.action(() => {
+ GlobalModel.activeMainView.set("clientsettings");
+ })();
+ }
+}
+
class BookmarksModel {
bookmarks: OArr = mobx.observable.array([], {
name: "Bookmarks",
@@ -3305,10 +3313,11 @@ class Model {
authKey: string;
isDev: boolean;
platform: string;
- activeMainView: OV<"plugins" | "session" | "history" | "bookmarks" | "webshare" | "connections"> =
- mobx.observable.box("session", {
- name: "activeMainView",
- });
+ activeMainView: OV<
+ "plugins" | "session" | "history" | "bookmarks" | "webshare" | "connections" | "clientsettings"
+ > = mobx.observable.box("session", {
+ name: "activeMainView",
+ });
termFontSize: CV;
alertMessage: OV = mobx.observable.box(null, {
name: "alertMessage",
@@ -3337,6 +3346,7 @@ class Model {
bookmarksModel: BookmarksModel;
historyViewModel: HistoryViewModel;
connectionViewModel: ConnectionsViewModel;
+ clientSettingsViewModel: ClientSettingsViewModel;
modalsModel: ModalsModel;
clientData: OV = mobx.observable.box(null, {
name: "clientData",
@@ -3360,6 +3370,7 @@ class Model {
this.bookmarksModel = new BookmarksModel();
this.historyViewModel = new HistoryViewModel();
this.connectionViewModel = new ConnectionsViewModel();
+ this.clientSettingsViewModel = new ClientSettingsViewModel();
this.remotesModalModel = new RemotesModalModel();
this.remotesModel = new RemotesModel();
this.modalsModel = new ModalsModel();
@@ -4794,6 +4805,10 @@ class CommandRunner {
GlobalModel.connectionViewModel.showConnectionsView();
}
+ clientSettingsView() {
+ GlobalModel.clientSettingsViewModel.showClientSettingsView();
+ }
+
historyView(params: HistorySearchParams) {
let kwargs = { nohist: "1" };
kwargs["offset"] = String(params.offset);