diff --git a/src/elements.tsx b/src/elements.tsx index f49ea19b..c54a22f0 100644 --- a/src/elements.tsx +++ b/src/elements.tsx @@ -247,4 +247,27 @@ class Markdown extends React.Component<{text : string, style? : any, extraClassN } } -export {CmdStrCode, Toggle, renderCmdText, RemoteStatusLight, InlineSettingsTextEdit, InfoMessage, Markdown}; +@mobxReact.observer +class SettingsError extends React.Component<{errorMessage : OV}, {}> { + @boundMethod + dismissError() : void { + mobx.action(() => { + this.props.errorMessage.set(null); + })(); + } + + render() { + if (this.props.errorMessage.get() == null) { + return null; + } + return ( +
+
Error: {this.props.errorMessage.get()}
+
+
+
+ ); + } +} + +export {CmdStrCode, Toggle, renderCmdText, RemoteStatusLight, InlineSettingsTextEdit, InfoMessage, Markdown, SettingsError}; diff --git a/src/main.tsx b/src/main.tsx index b6ed35a1..0b15fe85 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -13,7 +13,7 @@ import type * as T from "./types"; import localizedFormat from 'dayjs/plugin/localizedFormat'; import {GlobalModel, GlobalCommandRunner, Session, Cmd, ScreenLines, Screen, riToRPtr, TabColors, RemoteColors} from "./model"; import {windowWidthToCols, windowHeightToRows, termHeightFromRows, termWidthFromCols, getMonoFontSize} from "./textmeasure"; -import {isModKeyPress, boundInt, sortAndFilterRemotes} from "./util"; +import {isModKeyPress, boundInt, sortAndFilterRemotes, makeExternLink, isBlank} from "./util"; import {BookmarksView} from "./bookmarks"; import {HistoryView} from "./history"; import {Line, Prompt} from "./linecomps"; @@ -21,6 +21,7 @@ import {ScreenSettingsModal, SessionSettingsModal, LineSettingsModal, ClientSett import {RemotesModal} from "./remotes"; import {renderCmdText, RemoteStatusLight, Markdown} from "./elements"; import {LinesView} from "./linesview"; +import {TosModal} from "./modals"; dayjs.extend(localizedFormat) @@ -44,14 +45,6 @@ type InterObsValue = { timeoutid? : any, }; -function isBlank(s : string) : boolean { - return (s == null || s == ""); -} - -function makeExternLink(url : string) : string { - return "https://extern?" + encodeURIComponent(url); -} - function scrollDiv(div : any, amt : number) { if (div == null) { return; @@ -1976,6 +1969,9 @@ class Main extends React.Component<{}, {}> {
+ + + diff --git a/src/modals.tsx b/src/modals.tsx new file mode 100644 index 00000000..cff05392 --- /dev/null +++ b/src/modals.tsx @@ -0,0 +1,53 @@ +import * as React from "react"; +import * as mobxReact from "mobx-react"; +import * as mobx from "mobx"; +import {sprintf} from "sprintf-js"; +import {boundMethod} from "autobind-decorator"; +import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; +import cn from "classnames"; +import {GlobalModel, GlobalCommandRunner} from "./model"; +import * as util from "./util"; + +type OV = mobx.IObservableValue; + +class TosModal extends React.Component<{}, {}> { + @boundMethod + acceptTos() : void { + GlobalCommandRunner.clientAcceptTos(); + } + + render() { + return ( +
+
+
+
+
Welcome to [prompt]
+
+
+
+

Thank you for downloading Prompt!

+

+ Prompt is a new terminal designed to help you save time and organize your command life. + Prompt is currently in beta. If you'd like to give feedback, run into problems, have questions, + or need help, please join the Prompt discord server. +

+

+ Prompt is free to use, no email or registration required (unless you're using the cloud features). +

+

+ Full Terms of Service +

+
+
+
+
+
Accept Terms of Service
+
+
+
+ ); + } +} + +export {TosModal}; diff --git a/src/model.ts b/src/model.ts index 8c8e9c7f..ee2cd711 100644 --- a/src/model.ts +++ b/src/model.ts @@ -2448,6 +2448,14 @@ class Model { setTimeout(() => this.getClientDataLoop(1), 10); } + needsTos() : boolean { + let cdata = this.clientData.get(); + if (cdata == null) { + return false; + } + return (cdata.clientopts == null || !cdata.clientopts.acceptedtos); + } + refreshClient() : void { getApi().reloadWindow(); } @@ -3364,14 +3372,14 @@ class CommandRunner { GlobalModel.submitCommand("screen", "resize", null, {"nohist": "1", "screen": screenId, "cols": String(cols), "rows": String(rows)}, false); } - screenArchive(screenId : string, shouldArchive : boolean) { - GlobalModel.submitCommand("screen", "archive", [screenId, (shouldArchive ? "1" : "0")], {"nohist": "1"}, false); + screenArchive(screenId : string, shouldArchive : boolean) : Promise { + return GlobalModel.submitCommand("screen", "archive", [screenId, (shouldArchive ? "1" : "0")], {"nohist": "1"}, false); } - screenWebShare(screenId : string, shouldShare : boolean) { + screenWebShare(screenId : string, shouldShare : boolean) : Promise { let kwargs : Record = {"nohist": "1"}; kwargs["screen"] = screenId; - GlobalModel.submitCommand("screen", "webshare", [(shouldShare ? "1" : "0")], kwargs, true); + return GlobalModel.submitCommand("screen", "webshare", [(shouldShare ? "1" : "0")], kwargs, false); } showRemote(remoteid : string) { @@ -3456,11 +3464,11 @@ class CommandRunner { GlobalModel.submitCommand("screen", "set", null, {"focus": focusVal, "nohist": "1"}, false); } - screenSetSettings(screenId : string, settings : {tabcolor? : string, name? : string}) : void { + screenSetSettings(screenId : string, settings : {tabcolor? : string, name? : string}, interactive : boolean) : Promise { let kwargs = Object.assign({}, settings); kwargs["nohist"] = "1"; kwargs["screen"] = screenId; - GlobalModel.submitCommand("screen", "set", null, kwargs, true); + return GlobalModel.submitCommand("screen", "set", null, kwargs, interactive); } sessionSetSettings(sessionId : string, settings : {name? : string}) : void { @@ -3527,6 +3535,10 @@ class CommandRunner { GlobalModel.submitCommand("client", "set", null, kwargs, true); } + clientAcceptTos() : void { + GlobalModel.submitCommand("client", "accepttos", null, {"nohist": "1"}, true); + } + editBookmark(bookmarkId : string, desc : string, cmdstr : string) { let kwargs = { "nohist": "1", diff --git a/src/remotes.tsx b/src/remotes.tsx index a7502e01..f5563abe 100644 --- a/src/remotes.tsx +++ b/src/remotes.tsx @@ -370,7 +370,7 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
-
+
Error: {this.getErrorStr()}
diff --git a/src/settings.tsx b/src/settings.tsx index 3979d151..fb2c29cd 100644 --- a/src/settings.tsx +++ b/src/settings.tsx @@ -6,8 +6,8 @@ import {boundMethod} from "autobind-decorator"; import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; import cn from "classnames"; import {GlobalModel, GlobalCommandRunner, TabColors} from "./model"; -import {Toggle, RemoteStatusLight, InlineSettingsTextEdit} from "./elements"; -import {LineType, RendererPluginType, ClientDataType} from "./types"; +import {Toggle, RemoteStatusLight, InlineSettingsTextEdit, SettingsError} from "./elements"; +import {LineType, RendererPluginType, ClientDataType, CommandRtnType} from "./types"; import {PluginModel} from "./plugins"; import * as util from "./util"; @@ -24,13 +24,29 @@ const VERSION = __PROMPT_VERSION__; // @ts-ignore const BUILD = __PROMPT_BUILD__; +const WebShareMarkdown = ` +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. + +See [Terms of Service](https://www.getprompt.dev/tos.html) for more details. +`.trim(); + +function commandRtnHandler(prtn : Promise, errorMessage : OV) { + prtn.then((crtn) => { + if (crtn.success) { + return; + } + mobx.action(() => { + errorMessage.set(crtn.error); + })(); + }); +} + @mobxReact.observer class ScreenSettingsModal extends React.Component<{sessionId : string, screenId : string}, {}> { - tempName : OV; - tempTabColor : OV; - tempArchived : OV; - tempWebShared : OV; - shareCopied : OV = mobx.observable.box(false, {name: "sw-shareCopied"}); + shareCopied : OV = mobx.observable.box(false, {name: "ScreenSettings-shareCopied"}); + errorMessage : OV = mobx.observable.box(null, {name: "ScreenSettings-errorMessage"}); constructor(props : any) { super(props); @@ -39,10 +55,6 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId if (screen == null) { return; } - this.tempName = mobx.observable.box(screen.name.get(), {name: "screenSettings-tempName"}); - this.tempTabColor = mobx.observable.box(screen.getTabColor(), {name: "screenSettings-tempTabColor"}); - this.tempArchived = mobx.observable.box(screen.archived.get(), {name: "screenSettings-tempArchived"}); - this.tempWebShared = mobx.observable.box(screen.isWebShared(), {name: "screenSettings-tempWebShare"}); } @boundMethod @@ -53,58 +65,45 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId } @boundMethod - handleOK() : void { - mobx.action(() => { - GlobalModel.screenSettingsModal.set(null); - })(); - let screen = GlobalModel.getScreenById(this.props.sessionId, this.props.screenId); + selectTabColor(color : string) : void { + let {sessionId, screenId} = this.props; + let screen = GlobalModel.getScreenById(sessionId, screenId); if (screen == null) { return; } - let settings : {tabcolor? : string, name? : string} = {}; - if (this.tempTabColor.get() != screen.getTabColor()) { - settings.tabcolor = this.tempTabColor.get(); + if (screen.getTabColor() == color) { + return; } - if (this.tempName.get() != screen.name.get()) { - settings.name = this.tempName.get(); - } - if (Object.keys(settings).length > 0) { - GlobalCommandRunner.screenSetSettings(this.props.screenId, settings); - } - if (this.tempArchived.get() != screen.archived.get()) { - GlobalCommandRunner.screenArchive(screen.screenId, this.tempArchived.get()); - } - if (this.tempWebShared.get() != screen.isWebShared()) { - GlobalCommandRunner.screenWebShare(screen.screenId, this.tempWebShared.get()); - } - } - - @boundMethod - handleChangeName(e : any) : void { - mobx.action(() => { - this.tempName.set(e.target.value); - })(); - } - - @boundMethod - selectTabColor(color : string) : void { - mobx.action(() => { - this.tempTabColor.set(color); - })(); + let prtn = GlobalCommandRunner.screenSetSettings(this.props.screenId, {tabcolor: color}, false); + commandRtnHandler(prtn, this.errorMessage); } @boundMethod handleChangeArchived(val : boolean) : void { - mobx.action(() => { - this.tempArchived.set(val); - })(); + let {sessionId, screenId} = this.props; + let screen = GlobalModel.getScreenById(sessionId, screenId); + if (screen == null) { + return; + } + if (screen.archived.get() == val) { + return; + } + let prtn = GlobalCommandRunner.screenArchive(this.props.screenId, val); + commandRtnHandler(prtn, this.errorMessage); } @boundMethod handleChangeWebShare(val : boolean) : void { - mobx.action(() => { - this.tempWebShared.set(val); - })(); + let {sessionId, screenId} = this.props; + let screen = GlobalModel.getScreenById(sessionId, screenId); + if (screen == null) { + return; + } + if (screen.isWebShared() == val) { + return; + } + let prtn = GlobalCommandRunner.screenWebShare(screen.screenId, val); + commandRtnHandler(prtn, this.errorMessage); } @boundMethod @@ -129,13 +128,33 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId }, 600) } - webSharedUpdated() : boolean { + @boundMethod + inlineUpdateName(val : string) : void { let {sessionId, screenId} = this.props; let screen = GlobalModel.getScreenById(sessionId, screenId); if (screen == null) { - return null; + return; } - return screen.isWebShared() != this.tempWebShared.get(); + console.log("inline update name", val); + if (val == screen.name.get()) { + return; + } + let prtn = GlobalCommandRunner.screenSetSettings(this.props.screenId, {name: val}, false); + commandRtnHandler(prtn, this.errorMessage); + } + + @boundMethod + setErrorMessage(msg : string) : void { + mobx.action(() => { + this.errorMessage.set(msg); + })(); + } + + @boundMethod + dismissError() : void { + mobx.action(() => { + this.errorMessage.set(null); + })(); } render() { @@ -172,7 +191,7 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId Name
- +
@@ -182,10 +201,10 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId
- + - {this.tempTabColor.get()} + {screen.getTabColor()}
|
@@ -203,11 +222,7 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId Archived
- -
- will be archived - will be un-archived -
+
@@ -215,34 +230,21 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId Web Sharing
- -
- will be web-shared - will stop being web-shared - -
- copy share link - - - -
-
-
- +
- +
Share Link
- +
copy link @@ -252,10 +254,10 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId
+
diff --git a/src/sh2.less b/src/sh2.less index 7b70da5c..88dcdd92 100644 --- a/src/sh2.less +++ b/src/sh2.less @@ -51,6 +51,10 @@ html, body, #app, #main { background-color: #000; height: 100vh; + + a:hover { + color: #485fc7; + } } body { @@ -985,10 +989,6 @@ body::-webkit-scrollbar { a { color: #bbb; } - - a:hover { - color: #3273dc; - } } p.menu-label { @@ -2471,6 +2471,16 @@ input[type=checkbox] { .mono-font(inherit, 700); } +.tos-modal { + a:hover { + text-decoration: underline; + } + + .content { + .mono-font(13px); + } +} + .disconnected-modal { .modal-content { footer { @@ -3666,3 +3676,6 @@ body.prompt-webshare #main { } } +a.a-block { + display: block; +} diff --git a/src/types.ts b/src/types.ts index 32ba61be..ebe6ac19 100644 --- a/src/types.ts +++ b/src/types.ts @@ -439,6 +439,7 @@ type FeOptsType = { type ClientOptsType = { notelemetry : boolean, + acceptedtos : number, }; type ClientDataType = { diff --git a/src/util.ts b/src/util.ts index 9b972065..7b5125ac 100644 --- a/src/util.ts +++ b/src/util.ts @@ -329,4 +329,8 @@ function sortAndFilterRemotes(origRemotes : RemoteType[]) : RemoteType[] { return remotes; } -export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeDataMap, genMergeSimpleData, parseEnv0, boundInt, isModKeyPress, incObs, isBlank, loadFonts, getTodayStr, getYesterdayStr, getDateStr, sortAndFilterRemotes}; +function makeExternLink(url : string) : string { + return "https://extern?" + encodeURIComponent(url); +} + +export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeDataMap, genMergeSimpleData, parseEnv0, boundInt, isModKeyPress, incObs, isBlank, loadFonts, getTodayStr, getYesterdayStr, getDateStr, sortAndFilterRemotes, makeExternLink};