mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
tos, also redo screen settings so settings take affect immediately, working on smoother webshare flow
This commit is contained in:
+24
-1
@@ -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<string>}, {}> {
|
||||
@boundMethod
|
||||
dismissError() : void {
|
||||
mobx.action(() => {
|
||||
this.props.errorMessage.set(null);
|
||||
})();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.errorMessage.get() == null) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="settings-field settings-error">
|
||||
<div>Error: {this.props.errorMessage.get()}</div>
|
||||
<div className="flex-spacer"/>
|
||||
<div onClick={this.dismissError} className="error-dismiss"><i className="fa-sharp fa-solid fa-xmark"/></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {CmdStrCode, Toggle, renderCmdText, RemoteStatusLight, InlineSettingsTextEdit, InfoMessage, Markdown, SettingsError};
|
||||
|
||||
+5
-9
@@ -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<{}, {}> {
|
||||
<BookmarksView/>
|
||||
</div>
|
||||
<AlertModal/>
|
||||
<If condition={GlobalModel.needsTos()}>
|
||||
<TosModal/>
|
||||
</If>
|
||||
<If condition={GlobalModel.welcomeModalOpen.get()}>
|
||||
<WelcomeModal/>
|
||||
</If>
|
||||
|
||||
@@ -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<V> = mobx.IObservableValue<V>;
|
||||
|
||||
class TosModal extends React.Component<{}, {}> {
|
||||
@boundMethod
|
||||
acceptTos() : void {
|
||||
GlobalCommandRunner.clientAcceptTos();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={cn("modal tos-modal prompt-modal is-active")}>
|
||||
<div className="modal-background"/>
|
||||
<div className="modal-content">
|
||||
<header>
|
||||
<div className="modal-title">Welcome to [prompt]</div>
|
||||
</header>
|
||||
<div className="inner-content">
|
||||
<div className="content">
|
||||
<p>Thank you for downloading Prompt!</p>
|
||||
<p>
|
||||
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 <a target="_blank" href={util.makeExternLink("https://discord.gg/XfvZ334gwU")}>discord server</a>.
|
||||
</p>
|
||||
<p>
|
||||
Prompt is free to use, no email or registration required (unless you're using the cloud features).
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href={util.makeExternLink("https://www.getprompt.dev/tos.html")}>Full Terms of Service</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div className="flex-spacer"/>
|
||||
<div onClick={this.acceptTos} className="button is-prompt-green is-outlined is-small">Accept Terms of Service</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {TosModal};
|
||||
+18
-6
@@ -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<CommandRtnType> {
|
||||
return GlobalModel.submitCommand("screen", "archive", [screenId, (shouldArchive ? "1" : "0")], {"nohist": "1"}, false);
|
||||
}
|
||||
|
||||
screenWebShare(screenId : string, shouldShare : boolean) {
|
||||
screenWebShare(screenId : string, shouldShare : boolean) : Promise<CommandRtnType> {
|
||||
let kwargs : Record<string, string> = {"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<CommandRtnType> {
|
||||
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",
|
||||
|
||||
+1
-1
@@ -370,7 +370,7 @@ class CreateRemote extends React.Component<{model : RemotesModalModel, remoteEdi
|
||||
</div>
|
||||
</div>
|
||||
<If condition={!util.isBlank(this.getErrorStr())}>
|
||||
<div className="remoteedit-error">
|
||||
<div className="settings-field settings-error">
|
||||
Error: {this.getErrorStr()}
|
||||
</div>
|
||||
</If>
|
||||
|
||||
+83
-81
@@ -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<CommandRtnType>, errorMessage : OV<string>) {
|
||||
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<string>;
|
||||
tempTabColor : OV<string>;
|
||||
tempArchived : OV<boolean>;
|
||||
tempWebShared : OV<boolean>;
|
||||
shareCopied : OV<boolean> = mobx.observable.box(false, {name: "sw-shareCopied"});
|
||||
shareCopied : OV<boolean> = mobx.observable.box(false, {name: "ScreenSettings-shareCopied"});
|
||||
errorMessage : OV<string> = 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
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<input type="text" placeholder="Tab Name" onChange={this.handleChangeName} value={this.tempName.get()} maxLength={50}/>
|
||||
<InlineSettingsTextEdit placeholder="name" text={screen.name.get() ?? "(none)"} value={screen.name.get() ?? ""} onChange={this.inlineUpdateName} maxLength={50} showIcon={true}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
@@ -182,10 +201,10 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId
|
||||
<div className="settings-input">
|
||||
<div className="tab-colors">
|
||||
<div className="tab-color-cur">
|
||||
<span className={cn("icon tab-color-icon", "color-" + this.tempTabColor.get())}>
|
||||
<span className={cn("icon tab-color-icon", "color-" + screen.getTabColor())}>
|
||||
<i className="fa-sharp fa-solid fa-square"/>
|
||||
</span>
|
||||
<span>{this.tempTabColor.get()}</span>
|
||||
<span>{screen.getTabColor()}</span>
|
||||
</div>
|
||||
<div className="tab-color-sep">|</div>
|
||||
<For each="color" of={TabColors}>
|
||||
@@ -203,11 +222,7 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId
|
||||
Archived
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<Toggle checked={this.tempArchived.get()} onChange={this.handleChangeArchived}/>
|
||||
<div className="action-text">
|
||||
<If condition={this.tempArchived.get() && this.tempArchived.get() != screen.archived.get()}>will be archived</If>
|
||||
<If condition={!this.tempArchived.get() && this.tempArchived.get() != screen.archived.get()}>will be un-archived</If>
|
||||
</div>
|
||||
<Toggle checked={screen.archived.get()} onChange={this.handleChangeArchived}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
@@ -215,34 +230,21 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId
|
||||
Web Sharing
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<Toggle checked={this.tempWebShared.get()} onChange={this.handleChangeWebShare}/>
|
||||
<div className="action-text">
|
||||
<If condition={this.tempWebShared.get() && this.webSharedUpdated()}>will be web-shared</If>
|
||||
<If condition={!this.tempWebShared.get() && this.webSharedUpdated()}>will stop being web-shared</If>
|
||||
<If condition={screen.isWebShared() && !this.webSharedUpdated()}>
|
||||
<div className="button settings-share-link is-prompt-green is-outlined is-small" onClick={this.copyShareLink}>
|
||||
<span>copy share link</span>
|
||||
<span className="icon">
|
||||
<i className="fa-sharp fa-solid fa-copy"/>
|
||||
</span>
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
|
||||
<Toggle checked={screen.isWebShared()} onChange={this.handleChangeWebShare}/>
|
||||
</div>
|
||||
</div>
|
||||
<If condition={this.tempWebShared.get() && false}>
|
||||
<If condition={screen.isWebShared()}>
|
||||
<div className="settings-field sub-field">
|
||||
<div className="settings-label">
|
||||
Share Link
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<div className="button is-prompt-green is-outlined is-small" onClick={this.copyShareLink}>
|
||||
<a href={util.makeExternLink(screen.getWebShareUrl())} target="_blank" className="button is-prompt-green is-outlined is-small a-block">
|
||||
<span>open in browser</span>
|
||||
<span className="icon">
|
||||
<i className="fa-sharp fa-solid fa-up-right-from-square"/>
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<div className="button is-prompt-green is-outlined is-small ml-4" onClick={this.copyShareLink}>
|
||||
<span>copy link</span>
|
||||
<span className="icon">
|
||||
@@ -252,10 +254,10 @@ class ScreenSettingsModal extends React.Component<{sessionId : string, screenId
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
<SettingsError errorMessage={this.errorMessage}/>
|
||||
</div>
|
||||
<footer>
|
||||
<div onClick={this.closeModal} className="button is-prompt-cancel is-outlined is-small">Cancel</div>
|
||||
<div onClick={this.handleOK} className="button is-prompt-green is-outlined is-small">OK</div>
|
||||
<div onClick={this.closeModal} className="button is-prompt-green is-outlined is-small">Close</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+17
-4
@@ -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;
|
||||
}
|
||||
|
||||
@@ -439,6 +439,7 @@ type FeOptsType = {
|
||||
|
||||
type ClientOptsType = {
|
||||
notelemetry : boolean,
|
||||
acceptedtos : number,
|
||||
};
|
||||
|
||||
type ClientDataType = {
|
||||
|
||||
+5
-1
@@ -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};
|
||||
|
||||
Reference in New Issue
Block a user