diff --git a/buildSrc/DevBuild.js b/buildSrc/DevBuild.js
index 298142e7f79e..d95fef3143ab 100644
--- a/buildSrc/DevBuild.js
+++ b/buildSrc/DevBuild.js
@@ -69,7 +69,7 @@ export async function runDevBuild({ stage, host, desktop, clean, ignoreMigration
u2fAppId: `${protocol}//${hostname}:${port}/u2f-appid.json`,
giftCardBaseUrl: `${protocol}//${hostname}:${port}/giftcard`,
referralBaseUrl: `${protocol}//${hostname}:${port}/signup`,
- websiteBaseUrl: "https://tuta.com",
+ websiteBaseUrl: domainConfigs[hostname].websiteBaseUrl ?? "https://tuta.com",
},
}
}
@@ -223,7 +223,7 @@ globalThis.buildOptions.sqliteNativePath = "./better-sqlite3.node";`,
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const root = __dirname.split(path.sep).slice(0, -1).join(path.sep)
-async function createBootstrap(env, buildDir) {
+async function createBootstrap(env, buildDir, stage) {
let jsFileName
let htmlFileName
switch (env.mode) {
@@ -249,7 +249,7 @@ if (env.staticUrl == null && window.tutaoDefaultApiUrl) {
}
import('./app.js')`
await writeFile(`./${buildDir}/${jsFileName}`, template)
- const html = await LaunchHtml.renderHtml(imports, env)
+ const html = await LaunchHtml.renderHtml(imports, env, stage)
await writeFile(`./${buildDir}/${htmlFileName}`, html)
}
@@ -297,6 +297,6 @@ export async function prepareAssets(stage, host, version, domainConfigs, buildDi
/** @type {EnvMode[]} */
const modes = ["Browser", "App", "Desktop"]
for (const mode of modes) {
- await createBootstrap(env.create({ staticUrl: getStaticUrl(stage, mode, host), version, mode, dist: false, domainConfigs }), buildDir)
+ await createBootstrap(env.create({ staticUrl: getStaticUrl(stage, mode, host), version, mode, dist: false, domainConfigs }), buildDir, stage)
}
}
diff --git a/buildSrc/LaunchHtml.js b/buildSrc/LaunchHtml.js
index 4fcf65444974..a70b16c1b71f 100644
--- a/buildSrc/LaunchHtml.js
+++ b/buildSrc/LaunchHtml.js
@@ -21,10 +21,23 @@ function getCspUrls(env) {
}
}
+function getWebsiteUrl(stage) {
+ switch (stage) {
+ case "test":
+ return "https://test.tuta.com"
+ case "local":
+ return "https://local.tuta.com:9000"
+ default: // prod and host
+ return "https://tuta.com"
+ }
+}
+
/**
* Renders the initial HTML page to bootstrap Tutanota for different environments
*/
-export async function renderHtml(scripts, env) {
+export async function renderHtml(scripts, env, stage) {
+ // ideally check if it is possible to use the website url from the env.domainConfigs here instead of getWebsiteURL()
+ const websiteUrl = getWebsiteUrl(stage)
return `
@@ -45,7 +58,7 @@ export async function renderHtml(scripts, env) {
-
+
@@ -53,11 +66,11 @@ export async function renderHtml(scripts, env) {
content="Get a free email account with quantum-safe encryption and best privacy on all your devices. Green, secure & no ads!">
-
+
-
+
diff --git a/buildSrc/buildWebapp.js b/buildSrc/buildWebapp.js
index e7bb0856222b..8bfca0ba54ae 100644
--- a/buildSrc/buildWebapp.js
+++ b/buildSrc/buildWebapp.js
@@ -177,10 +177,11 @@ self.onmessage = function (msg) {
dist: true,
domainConfigs,
}),
+ stage,
app,
)
if (stage !== "release") {
- await createHtml(env.create({ staticUrl: restUrl, version, mode: "App", dist: true, domainConfigs }), app)
+ await createHtml(env.create({ staticUrl: restUrl, version, mode: "App", dist: true, domainConfigs }), stage, app)
}
await bundleServiceWorker(chunks, version, minify, buildDir)
diff --git a/buildSrc/createHtml.js b/buildSrc/createHtml.js
index 51ec231f08c7..1dd04a486ec6 100644
--- a/buildSrc/createHtml.js
+++ b/buildSrc/createHtml.js
@@ -14,9 +14,10 @@ import path from "node:path"
* staticUrl: String defining app base url for non-production environments and the native clients.
* versionNumber: String containing the app's version number
* @param app App to be built, defaults to mail app {String}
+ * @param stage Deployment for which to build: 'prod' will build for the production system, 'test' for the test system, 'local' will use local.
* @returns {Promise[]>}
*/
-export async function createHtml(env, app = "mail") {
+export async function createHtml(env, stage, app = "mail") {
let jsFileName
let htmlFileName
const buildDir = app === "calendar" ? "build-calendar-app" : "build"
@@ -44,7 +45,7 @@ window.env = ${JSON.stringify(env, null, 2)}
${indexTemplate}`
return Promise.all([
_writeFile(`./${buildDir}/${jsFileName}`, index),
- renderHtml(imports, env).then((content) => _writeFile(`./${buildDir}/${htmlFileName}`, content)),
+ renderHtml(imports, env, stage).then((content) => _writeFile(`./${buildDir}/${htmlFileName}`, content)),
])
}
diff --git a/desktop.js b/desktop.js
index c496cfbc4f72..8369bf1914d1 100644
--- a/desktop.js
+++ b/desktop.js
@@ -112,7 +112,7 @@ async function buildDesktopClient(version, { stage, host, platform, architecture
}
if (stage === "release") {
- await createHtml(env.create({ staticUrl: tutaAppUrl, version, mode: "Desktop", dist: true, domainConfigs }))
+ await createHtml(env.create({ staticUrl: tutaAppUrl, version, mode: "Desktop", dist: true, domainConfigs }), stage)
await buildDesktop(desktopBaseOpts)
if (!customDesktopRelease) {
const updateUrl = new URL(tutaTestUrl)
@@ -124,7 +124,7 @@ async function buildDesktopClient(version, { stage, host, platform, architecture
// Do not notarize test build
notarize: false,
})
- await createHtml(env.create({ staticUrl: tutaTestUrl, version, mode: "Desktop", dist: true, domainConfigs }))
+ await createHtml(env.create({ staticUrl: tutaTestUrl, version, mode: "Desktop", dist: true, domainConfigs }), stage)
await buildDesktop(desktopTestOpts)
}
} else if (stage === "local") {
@@ -140,7 +140,7 @@ async function buildDesktopClient(version, { stage, host, platform, architecture
nameSuffix: "-snapshot",
notarize: false,
})
- await createHtml(env.create({ staticUrl: `http://${addr}:9000`, version, mode: "Desktop", dist: true, domainConfigs }))
+ await createHtml(env.create({ staticUrl: `http://${addr}:9000`, version, mode: "Desktop", dist: true, domainConfigs }), stage)
await buildDesktop(desktopLocalOpts)
} else if (stage === "test") {
const updateUrl = new URL(tutaTestUrl)
@@ -150,7 +150,7 @@ async function buildDesktopClient(version, { stage, host, platform, architecture
nameSuffix: "-test",
notarize: false,
})
- await createHtml(env.create({ staticUrl: tutaTestUrl, version, mode: "Desktop", dist: true, domainConfigs }))
+ await createHtml(env.create({ staticUrl: tutaTestUrl, version, mode: "Desktop", dist: true, domainConfigs }), stage)
await buildDesktop(desktopTestOpts)
} else if (stage === "prod") {
const desktopProdOpts = Object.assign({}, desktopBaseOpts, {
@@ -158,7 +158,7 @@ async function buildDesktopClient(version, { stage, host, platform, architecture
updateUrl: "http://localhost:9000/desktop",
notarize: false,
})
- await createHtml(env.create({ staticUrl: tutaAppUrl, version, mode: "Desktop", dist: true, domainConfigs }))
+ await createHtml(env.create({ staticUrl: tutaAppUrl, version, mode: "Desktop", dist: true, domainConfigs }), stage)
await buildDesktop(desktopProdOpts)
} else {
// stage = host
@@ -168,7 +168,7 @@ async function buildDesktopClient(version, { stage, host, platform, architecture
nameSuffix: "-snapshot",
notarize: false,
})
- await createHtml(env.create({ staticUrl: host, version, mode: "Desktop", dist: true, domainConfigs }))
+ await createHtml(env.create({ staticUrl: host, version, mode: "Desktop", dist: true, domainConfigs }), stage)
await buildDesktop(desktopHostOpts)
}
}
diff --git a/src/calendar-app/calendar-app.ts b/src/calendar-app/calendar-app.ts
index 6aef1cebf391..80b72dc36a42 100644
--- a/src/calendar-app/calendar-app.ts
+++ b/src/calendar-app/calendar-app.ts
@@ -1,7 +1,7 @@
import { client } from "../common/misc/ClientDetector.js"
import m from "mithril"
import Mithril, { Children, ClassComponent, Component, RouteDefs, RouteResolver, Vnode, VnodeDOM } from "mithril"
-import { lang, languageCodeToTag, languages } from "../common/misc/LanguageViewModel.js"
+import { lang, languageCodeToTag, languages, setInfoLinks } from "../common/misc/LanguageViewModel.js"
import { root } from "../RootView.js"
import { disableErrorHandlingDuringLogout, handleUncaughtError } from "../common/misc/ErrorHandler.js"
import { assertMainOrNodeBoot, bootFinished, isApp, isDesktop, isOfflineStorageAvailable } from "../common/api/common/Env.js"
@@ -397,6 +397,8 @@ import("../mail-app/translations/en.js")
const serviceworker = await import("../common/serviceworker/ServiceWorkerClient.js")
serviceworker.init(domainConfig)
+ setInfoLinks(domainConfig.websiteBaseUrl)
+
printJobsMessage(domainConfig)
})
diff --git a/src/common/gui/RenderLoginInfoLinks.ts b/src/common/gui/RenderLoginInfoLinks.ts
index 1074f4b9a3f0..e278d327b074 100644
--- a/src/common/gui/RenderLoginInfoLinks.ts
+++ b/src/common/gui/RenderLoginInfoLinks.ts
@@ -1,7 +1,7 @@
import m, { Children } from "mithril"
import { isApp, isDesktop } from "../api/common/Env.js"
import { ExternalLink } from "./base/ExternalLink.js"
-import { InfoLink, lang } from "../misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../misc/LanguageViewModel.js"
import { createDropdown } from "./base/Dropdown.js"
import { mapNullable } from "@tutao/tutanota-utils"
import { getWhitelabelCustomizations } from "../misc/WhitelabelCustomizations.js"
@@ -48,11 +48,11 @@ export function renderInfoLinks(): Children {
}
function getImprintLink(): string | null {
- return mapNullable(getWhitelabelCustomizations(window), (c) => c.imprintUrl) || InfoLink.About
+ return mapNullable(getWhitelabelCustomizations(window), (c) => c.imprintUrl) || InfoLinks.About
}
function getPrivacyStatementLink(): string | null {
- return mapNullable(getWhitelabelCustomizations(window), (c) => c.privacyStatementUrl) || InfoLink.Privacy
+ return mapNullable(getWhitelabelCustomizations(window), (c) => c.privacyStatementUrl) || InfoLinks.Privacy
}
/**
diff --git a/src/common/login/recover/TakeOverDeletedAddressDialog.ts b/src/common/login/recover/TakeOverDeletedAddressDialog.ts
index 602b2e2c9b74..d8bed7316fab 100644
--- a/src/common/login/recover/TakeOverDeletedAddressDialog.ts
+++ b/src/common/login/recover/TakeOverDeletedAddressDialog.ts
@@ -3,7 +3,7 @@ import stream from "mithril/stream"
import { AccessBlockedError, AccessDeactivatedError, InvalidDataError, NotAuthenticatedError, TooManyRequestsError } from "../../api/common/error/RestError"
import { showProgressDialog } from "../../gui/dialogs/ProgressDialog"
import { isMailAddress } from "../../misc/FormatValidator.js"
-import { InfoLink, lang } from "../../misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../../misc/LanguageViewModel.js"
import { Autocomplete, TextField, TextFieldType } from "../../gui/base/TextField.js"
import { Dialog, DialogType } from "../../gui/base/Dialog"
import { HtmlEditor, HtmlEditorMode } from "../../gui/editor/HtmlEditor"
@@ -27,7 +27,7 @@ export function showTakeOverDialog(mailAddress: string, password: string): Dialo
view: () => {
return [
m(".mt", lang.get("takeOverUnusedAddress_msg")),
- m(MoreInfoLink, { link: InfoLink.InactiveAccounts }),
+ m(MoreInfoLink, { link: InfoLinks.InactiveAccounts }),
m(TextField, {
label: "targetAddress_label",
value: targetAccountAddress(),
diff --git a/src/common/misc/LanguageViewModel.ts b/src/common/misc/LanguageViewModel.ts
index 154008665992..955551b04f88 100644
--- a/src/common/misc/LanguageViewModel.ts
+++ b/src/common/misc/LanguageViewModel.ts
@@ -1,5 +1,4 @@
-import type { lazy } from "@tutao/tutanota-utils"
-import { downcast, typedEntries } from "@tutao/tutanota-utils"
+import { downcast, lazy, typedEntries } from "@tutao/tutanota-utils"
import type { TranslationKeyType } from "./TranslationKey"
import { getWhitelabelCustomizations, WhitelabelCustomizations } from "./WhitelabelCustomizations"
import { assertMainOrNodeBoot } from "../api/common/Env"
@@ -194,34 +193,69 @@ export const languageNative: ReadonlyArray<{
}
})
-export const enum InfoLink {
- HomePage = "https://tuta.com",
- About = "https://tuta.com/imprint",
+// Modifiable so `app.js` can initialize it to the website urls in the domain config
+export let InfoLinks = {
+ HomePage: "https://tuta.com",
+ About: `https://tuta.com/imprint`,
//terms
- Terms = "https://tuta.com/terms",
- Privacy = "https://tuta.com/privacy-policy",
- GiftCardsTerms = "https://tuta.com/giftCardsTerms",
+ Terms: `https://tuta.com/terms`,
+ Privacy: `https://tuta.com/privacy-policy`,
+ GiftCardsTerms: `https://tuta.com/giftCardsTerms`,
//faq
- RecoverCode = "https://tuta.com/faq#reset",
- SecondFactor = "https://tuta.com/faq#2fa",
- SpamRules = "https://tuta.com/faq#spam",
- DomainInfo = "https://tuta.com/faq#custom-domain",
- Whitelabel = "https://tuta.com/faq#whitelabel",
- ReferralLink = "https://tuta.com/faq#refer-a-friend",
- Webview = "https://tuta.com/faq#webview",
- Phishing = "https://tuta.com/faq#phishing",
- MailAuth = "https://tuta.com/faq#mail-auth",
- RunInBackground = "https://tuta.com/faq#tray-desktop",
- LoadImages = "https://tuta.com/faq#load-images",
- Usage = "https://tuta.com/faq#usage",
- Download = "https://tuta.com/#download",
- SharedMailboxes = "https://tuta.com/support/#shared-mailboxes",
- InactiveAccounts = "https://tuta.com/faq/#inactive-accounts",
- AppStorePaymentChange = "https://tuta.com/support/#appstore-payment-change",
- AppStorePayment = "https://tuta.com/support/#appstore-payments",
- AppStoreDowngrade = "https://tuta.com/support/#appstore-subscription-downgrade",
- PasswordGenerator = "https://tuta.com/faq#passphrase-generator",
- HomePageFreeSignup = "https://tuta.com/free-email",
+ RecoverCode: `https://tuta.com/faq#reset`,
+ SecondFactor: `https://tuta.com/faq#2fa`,
+ SpamRules: `https://tuta.com/faq#spam`,
+ DomainInfo: `https://tuta.com/faq#custom-domain`,
+ Whitelabel: `https://tuta.com/faq#whitelabel`,
+ ReferralLink: `https://tuta.com/faq#refer-a-friend`,
+ Webview: `https://tuta.com/faq#webview`,
+ Phishing: `https://tuta.com/faq#phishing`,
+ MailAuth: `https://tuta.com/faq#mail-auth`,
+ RunInBackground: `https://tuta.com/faq#tray-desktop`,
+ LoadImages: `https://tuta.com/faq#load-images`,
+ Usage: `https://tuta.com/faq#usage`,
+ Download: `https://tuta.com/#download`,
+ SharedMailboxes: `https://tuta.com/support/#shared-mailboxes`,
+ InactiveAccounts: `https://tuta.com/faq/#inactive-accounts`,
+ AppStorePaymentChange: `https://tuta.com/support/#appstore-payment-change`,
+ AppStorePayment: `https://tuta.com/support/#appstore-payments`,
+ AppStoreDowngrade: `https://tuta.com/support/#appstore-subscription-downgrade`,
+ PasswordGenerator: `https://tuta.com/faq#passphrase-generator`,
+ HomePageFreeSignup: `https://tuta.com/free-email`,
+}
+export type InfoLink = (typeof InfoLinks)[keyof typeof InfoLinks]
+
+// Updates the website links in `InfoLinks` to use `websiteUrl` as the root
+export function setInfoLinks(websiteUrl: string) {
+ InfoLinks = {
+ HomePage: websiteUrl,
+ About: `${websiteUrl}/imprint`,
+ //terms
+ Terms: `${websiteUrl}/terms`,
+ Privacy: `${websiteUrl}/privacy-policy`,
+ GiftCardsTerms: `${websiteUrl}/giftCardsTerms`,
+ //faq
+ RecoverCode: `${websiteUrl}/faq#reset`,
+ SecondFactor: `${websiteUrl}/faq#2fa`,
+ SpamRules: `${websiteUrl}/faq#spam`,
+ DomainInfo: `${websiteUrl}/faq#custom-domain`,
+ Whitelabel: `${websiteUrl}/faq#whitelabel`,
+ ReferralLink: `${websiteUrl}/faq#refer-a-friend`,
+ Webview: `${websiteUrl}/faq#webview`,
+ Phishing: `${websiteUrl}/faq#phishing`,
+ MailAuth: `${websiteUrl}/faq#mail-auth`,
+ RunInBackground: `${websiteUrl}/faq#tray-desktop`,
+ LoadImages: `${websiteUrl}/faq#load-images`,
+ Usage: `${websiteUrl}/faq#usage`,
+ Download: `${websiteUrl}/#download`,
+ SharedMailboxes: `${websiteUrl}/support/#shared-mailboxes`,
+ InactiveAccounts: `${websiteUrl}/faq/#inactive-accounts`,
+ AppStorePaymentChange: `${websiteUrl}/support/#appstore-payment-change`,
+ AppStorePayment: `${websiteUrl}/support/#appstore-payments`,
+ AppStoreDowngrade: `${websiteUrl}/support/#appstore-subscription-downgrade`,
+ PasswordGenerator: `${websiteUrl}/faq#passphrase-generator`,
+ HomePageFreeSignup: `${websiteUrl}/free-email`,
+ }
}
/**
diff --git a/src/common/misc/news/MoreInfoLink.ts b/src/common/misc/news/MoreInfoLink.ts
index fc36bb4ae9af..516f39a20273 100644
--- a/src/common/misc/news/MoreInfoLink.ts
+++ b/src/common/misc/news/MoreInfoLink.ts
@@ -1,4 +1,4 @@
-import { InfoLink, lang } from "../LanguageViewModel.js"
+import { InfoLink, InfoLinks, lang } from "../LanguageViewModel.js"
import m, { Children, Component, Vnode } from "mithril"
import { ExternalLink, relDocument } from "../../gui/base/ExternalLink.js"
@@ -15,17 +15,17 @@ export class MoreInfoLink implements Component {
view(vnode: Vnode): Children {
let specialType: relDocument | undefined
switch (vnode.attrs.link) {
- case InfoLink.HomePage:
+ case InfoLinks.HomePage:
specialType = "me"
break
- case InfoLink.About:
+ case InfoLinks.About:
specialType = "license"
break
- case InfoLink.Privacy:
+ case InfoLinks.Privacy:
specialType = "privacy-policy"
break
- case InfoLink.Terms:
- case InfoLink.GiftCardsTerms:
+ case InfoLinks.Terms:
+ case InfoLinks.GiftCardsTerms:
specialType = "terms-of-service"
break
default:
diff --git a/src/common/misc/news/items/NewPlansNews.ts b/src/common/misc/news/items/NewPlansNews.ts
index d15601d2bea0..bf12edeff8e7 100644
--- a/src/common/misc/news/items/NewPlansNews.ts
+++ b/src/common/misc/news/items/NewPlansNews.ts
@@ -1,7 +1,7 @@
import { NewsListItem } from "../NewsListItem.js"
import m, { Children } from "mithril"
import { NewsId } from "../../../api/entities/tutanota/TypeRefs.js"
-import { InfoLink, lang } from "../../LanguageViewModel.js"
+import { InfoLinks, lang } from "../../LanguageViewModel.js"
import { Button, ButtonAttrs, ButtonType } from "../../../gui/base/Button.js"
import { NewsModel } from "../NewsModel.js"
import { UserController } from "../../../api/main/UserController.js"
@@ -23,7 +23,7 @@ export class NewPlansNews implements NewsListItem {
}
render(newsId: NewsId): Children {
- const lnk = InfoLink.Privacy
+ const lnk = InfoLinks.Privacy
const acknowledgeAction = () => {
this.newsModel.acknowledgeNews(newsId.newsItemId).then(m.redraw)
diff --git a/src/common/misc/news/items/NewPlansOfferEndingNews.ts b/src/common/misc/news/items/NewPlansOfferEndingNews.ts
index 2cb2e8667b71..5e906fd79cd3 100644
--- a/src/common/misc/news/items/NewPlansOfferEndingNews.ts
+++ b/src/common/misc/news/items/NewPlansOfferEndingNews.ts
@@ -1,7 +1,7 @@
import { NewsListItem } from "../NewsListItem.js"
import m, { Children } from "mithril"
import { NewsId } from "../../../api/entities/tutanota/TypeRefs.js"
-import { InfoLink, lang } from "../../LanguageViewModel.js"
+import { lang } from "../../LanguageViewModel.js"
import { Button, ButtonAttrs, ButtonType } from "../../../gui/base/Button.js"
import { NewsModel } from "../NewsModel.js"
import { UserController } from "../../../api/main/UserController.js"
diff --git a/src/common/misc/news/items/ReferralLinkViewer.ts b/src/common/misc/news/items/ReferralLinkViewer.ts
index 1e56ece26fe2..afb21ff78037 100644
--- a/src/common/misc/news/items/ReferralLinkViewer.ts
+++ b/src/common/misc/news/items/ReferralLinkViewer.ts
@@ -1,4 +1,4 @@
-import { InfoLink, lang } from "../../LanguageViewModel.js"
+import { InfoLinks, lang } from "../../LanguageViewModel.js"
import { isApp } from "../../../api/common/Env.js"
import { locator } from "../../../api/main/CommonLocator.js"
import { copyToClipboard } from "../../ClipboardUtils.js"
@@ -37,7 +37,7 @@ export class ReferralLinkViewer implements Component {
label: "referralLink_label",
value: referralLink,
injectionsRight: () => this.renderButtons(referralLink),
- helpLabel: () => ifAllowedTutaLinks(locator.logins, InfoLink.ReferralLink, (link) => [m(MoreInfoLink, { link: link })]),
+ helpLabel: () => ifAllowedTutaLinks(locator.logins, InfoLinks.ReferralLink, (link) => [m(MoreInfoLink, { link: link })]),
}
}
diff --git a/src/common/misc/news/items/UsageOptInNews.ts b/src/common/misc/news/items/UsageOptInNews.ts
index a4544ac97076..f4cd0302043d 100644
--- a/src/common/misc/news/items/UsageOptInNews.ts
+++ b/src/common/misc/news/items/UsageOptInNews.ts
@@ -2,7 +2,7 @@ import { NewsListItem } from "../NewsListItem.js"
import m, { Children } from "mithril"
import { NewsId } from "../../../api/entities/tutanota/TypeRefs.js"
import { locator } from "../../../api/main/CommonLocator.js"
-import { InfoLink, lang } from "../../LanguageViewModel.js"
+import { InfoLinks, lang } from "../../LanguageViewModel.js"
import { Dialog } from "../../../gui/base/Dialog.js"
import { Button, ButtonAttrs, ButtonType } from "../../../gui/base/Button.js"
import { NewsModel } from "../NewsModel.js"
@@ -66,7 +66,7 @@ export class UsageOptInNews implements NewsListItem {
m("li", lang.get("userUsageDataOptInStatement3_msg")),
m("li", lang.get("userUsageDataOptInStatement4_msg")),
]),
- m(MoreInfoLink, { link: InfoLink.Privacy }),
+ m(MoreInfoLink, { link: InfoLinks.Privacy }),
m(
".flex-end.flex-no-grow-no-shrink-auto.flex-wrap",
buttonAttrs.map((a) => m(Button, a)),
diff --git a/src/common/misc/passwords/PasswordGeneratorDialog.ts b/src/common/misc/passwords/PasswordGeneratorDialog.ts
index 6a2e878c5df0..7b9b6679bc66 100644
--- a/src/common/misc/passwords/PasswordGeneratorDialog.ts
+++ b/src/common/misc/passwords/PasswordGeneratorDialog.ts
@@ -5,7 +5,7 @@ import { Button, ButtonType } from "../../gui/base/Button.js"
import { locator } from "../../api/main/CommonLocator"
import { px } from "../../gui/size"
import { copyToClipboard } from "../ClipboardUtils"
-import { InfoLink, lang } from "../LanguageViewModel.js"
+import { InfoLinks, lang } from "../LanguageViewModel.js"
import { LoginButton } from "../../gui/base/buttons/LoginButton.js"
import { ExternalLink } from "../../gui/base/ExternalLink.js"
@@ -76,7 +76,7 @@ class PasswordGeneratorDialog implements Component
lang.get("passphraseGeneratorHelp_msg"),
" ",
m(ExternalLink, {
- href: InfoLink.PasswordGenerator,
+ href: InfoLinks.PasswordGenerator,
text: lang.get("faqEntry_label"),
isCompanySite: true,
}),
diff --git a/src/common/settings/AboutDialog.ts b/src/common/settings/AboutDialog.ts
index ddd3a253763f..d0f834ae2303 100644
--- a/src/common/settings/AboutDialog.ts
+++ b/src/common/settings/AboutDialog.ts
@@ -3,7 +3,7 @@ import { Button, ButtonType } from "../gui/base/Button.js"
import { getLightOrDarkTutaLogo } from "../gui/theme.js"
import { showUserError } from "../misc/ErrorHandlerImpl.js"
import { locator } from "../api/main/CommonLocator.js"
-import { InfoLink, lang } from "../misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../misc/LanguageViewModel.js"
import { newMailEditorFromTemplate } from "../../mail-app/mail/editor/MailEditor.js"
import { UserError } from "../api/main/UserError.js"
import { clientInfoString, getLogAttachments } from "../misc/ErrorReporter.js"
@@ -32,7 +32,7 @@ export class AboutDialog implements Component {
m.trust(getLightOrDarkTutaLogo(client.isCalendarApp())),
),
m(".flex.justify-center.flex-wrap", [
- m(ExternalLink, { href: InfoLink.HomePage, text: "Website", isCompanySite: true, specialType: "me", class: "mlr mt" }),
+ m(ExternalLink, { href: InfoLinks.HomePage, text: "Website", isCompanySite: true, specialType: "me", class: "mlr mt" }),
m(ExternalLink, {
href: "https://github.com/tutao/tutanota/releases",
text: "Releases",
diff --git a/src/common/settings/EditNotificationEmailDialog.ts b/src/common/settings/EditNotificationEmailDialog.ts
index 42b7c03f3aa2..ff0fef10d13b 100644
--- a/src/common/settings/EditNotificationEmailDialog.ts
+++ b/src/common/settings/EditNotificationEmailDialog.ts
@@ -1,7 +1,7 @@
import type { Booking, CustomerInfo, CustomerProperties, NotificationMailTemplate } from "../api/entities/sys/TypeRefs.js"
import { BookingTypeRef, createNotificationMailTemplate, CustomerInfoTypeRef, CustomerPropertiesTypeRef } from "../api/entities/sys/TypeRefs.js"
import { HtmlEditor } from "../gui/editor/HtmlEditor.js"
-import { InfoLink, lang, languages } from "../misc/LanguageViewModel.js"
+import { InfoLinks, lang, languages } from "../misc/LanguageViewModel.js"
import stream from "mithril/stream"
import Stream from "mithril/stream"
import { Dialog, DialogType } from "../gui/base/Dialog.js"
@@ -261,7 +261,7 @@ function getDefaultNotificationMail(): string {
HTML_PTAG_END +
HTML_PTAG_START +
lang.get("externalNotificationMailBody2_msg", {
- "{1}": InfoLink.HomePage,
+ "{1}": InfoLinks.HomePage,
}) +
HTML_PTAG_END +
HTML_PTAG_START +
diff --git a/src/common/settings/login/LoginSettingsViewer.ts b/src/common/settings/login/LoginSettingsViewer.ts
index dfc6f30e4cc9..715f410d089e 100644
--- a/src/common/settings/login/LoginSettingsViewer.ts
+++ b/src/common/settings/login/LoginSettingsViewer.ts
@@ -2,7 +2,7 @@ import m, { Children } from "mithril"
import stream from "mithril/stream"
import type { TextFieldAttrs } from "../../gui/base/TextField.js"
import { TextField } from "../../gui/base/TextField.js"
-import { InfoLink, lang } from "../../misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../../misc/LanguageViewModel.js"
import { Icons } from "../../gui/base/icons/Icons.js"
import { CustomerPropertiesTypeRef, Session, SessionTypeRef } from "../../api/entities/sys/TypeRefs.js"
import { assertNotNull, LazyLoaded, neverNull, ofClass } from "@tutao/tutanota-utils"
@@ -108,7 +108,7 @@ export class LoginSettingsViewer implements UpdatableSettingsViewer {
const recoveryCodeFieldAttrs: TextFieldAttrs = {
label: "recoveryCode_label",
helpLabel: () => {
- return ifAllowedTutaLinks(locator.logins, InfoLink.RecoverCode, (link) => [m(MoreInfoLink, { link: link })])
+ return ifAllowedTutaLinks(locator.logins, InfoLinks.RecoverCode, (link) => [m(MoreInfoLink, { link: link })])
},
value: this._stars(),
oninput: this._stars,
@@ -137,7 +137,7 @@ export class LoginSettingsViewer implements UpdatableSettingsViewer {
this._usageTestModel.setOptInDecision(assertNotNull(v))
},
helpLabel: () => {
- return ifAllowedTutaLinks(locator.logins, InfoLink.Usage, (link) => [
+ return ifAllowedTutaLinks(locator.logins, InfoLinks.Usage, (link) => [
m("span", lang.get("userUsageDataOptInInfo_msg") + " "),
m(MoreInfoLink, { link: link }),
])
diff --git a/src/common/settings/login/RecoverCodeDialog.ts b/src/common/settings/login/RecoverCodeDialog.ts
index 86868b0ca2de..4d055800971d 100644
--- a/src/common/settings/login/RecoverCodeDialog.ts
+++ b/src/common/settings/login/RecoverCodeDialog.ts
@@ -1,4 +1,4 @@
-import { InfoLink, lang } from "../../misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../../misc/LanguageViewModel.js"
import { Dialog, DialogType } from "../../gui/base/Dialog.js"
import { assertNotNull, Hex, noOp, ofClass } from "@tutao/tutanota-utils"
import m, { Child, Children, Vnode } from "mithril"
@@ -131,7 +131,7 @@ export class RecoverCodeField {
}
private renderRecoveryText(): Child {
- const link = InfoLink.RecoverCode
+ const link = InfoLinks.RecoverCode
return m(".pt.pb", [lang.get("recoveryCode_msg"), m("", [m(MoreInfoLink, { link, isSmall: true })])])
}
}
diff --git a/src/common/settings/login/secondfactor/SecondFactorsEditForm.ts b/src/common/settings/login/secondfactor/SecondFactorsEditForm.ts
index 5fd8515e4870..0f73e64b449b 100644
--- a/src/common/settings/login/secondfactor/SecondFactorsEditForm.ts
+++ b/src/common/settings/login/secondfactor/SecondFactorsEditForm.ts
@@ -5,7 +5,7 @@ import { SecondFactorTypeRef } from "../../../api/entities/sys/TypeRefs.js"
import { assertNotNull, LazyLoaded, neverNull, ofClass } from "@tutao/tutanota-utils"
import { Icons } from "../../../gui/base/icons/Icons.js"
import { Dialog } from "../../../gui/base/Dialog.js"
-import { InfoLink, lang } from "../../../misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../../../misc/LanguageViewModel.js"
import { assertEnumValue, SecondFactorType } from "../../../api/common/TutanotaConstants.js"
import { showProgressDialog } from "../../../gui/dialogs/ProgressDialog.js"
import type { TableAttrs, TableLineAttrs } from "../../../gui/base/Table.js"
@@ -50,7 +50,7 @@ export class SecondFactorsEditForm {
m(".h4.mt-l", lang.get("secondFactorAuthentication_label")),
m(Table, secondFactorTableAttrs),
this.domainConfigProvider.getCurrentDomainConfig().firstPartyDomain
- ? [ifAllowedTutaLinks(locator.logins, InfoLink.SecondFactor, (link) => m(MoreInfoLink, { link: link, isSmall: true }))]
+ ? [ifAllowedTutaLinks(locator.logins, InfoLinks.SecondFactor, (link) => m(MoreInfoLink, { link: link, isSmall: true }))]
: null,
]
}
diff --git a/src/common/settings/whitelabel/WhitelabelSettingsViewer.ts b/src/common/settings/whitelabel/WhitelabelSettingsViewer.ts
index 1a0ff27178b7..271eb29d01d5 100644
--- a/src/common/settings/whitelabel/WhitelabelSettingsViewer.ts
+++ b/src/common/settings/whitelabel/WhitelabelSettingsViewer.ts
@@ -20,7 +20,7 @@ import {
CustomerTypeRef,
WhitelabelConfigTypeRef,
} from "../../api/entities/sys/TypeRefs.js"
-import { InfoLink, lang } from "../../misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../../misc/LanguageViewModel.js"
import { FeatureType, OperationType } from "../../api/common/TutanotaConstants.js"
import { progressIcon } from "../../gui/base/Icon.js"
import { showProgressDialog } from "../../gui/dialogs/ProgressDialog.js"
@@ -88,7 +88,7 @@ export class WhitelabelSettingsViewer implements UpdatableSettingsViewer {
? [
m(".h4.mt-l", lang.get("whitelabel_label")),
m(".small", lang.get("whitelabelDomainLinkInfo_msg") + " "),
- m("small.text-break", [m(`a[href=${InfoLink.Whitelabel}][target=_blank]`, InfoLink.Whitelabel)]),
+ m("small.text-break", [m(`a[href=${InfoLinks.Whitelabel}][target=_blank]`, InfoLinks.Whitelabel)]),
this._renderWhitelabelStatusSettings(),
this._renderNotificationEmailSettings(),
m(".h4.mt-l", lang.get("whitelabelDomain_label")),
diff --git a/src/common/subscription/PaymentViewer.ts b/src/common/subscription/PaymentViewer.ts
index 7cf1aa6a4a12..1fa76cf3c259 100644
--- a/src/common/subscription/PaymentViewer.ts
+++ b/src/common/subscription/PaymentViewer.ts
@@ -1,7 +1,7 @@
import m, { Children } from "mithril"
import { assertMainOrNode, isIOSApp } from "../api/common/Env"
import { assertNotNull, last, neverNull, ofClass } from "@tutao/tutanota-utils"
-import { InfoLink, lang, TranslationKey } from "../misc/LanguageViewModel"
+import { InfoLinks, lang, TranslationKey } from "../misc/LanguageViewModel"
import {
AccountingInfo,
AccountingInfoTypeRef,
@@ -151,7 +151,7 @@ export class PaymentViewer implements UpdatableSettingsViewer {
// they must downgrade to Free first.
const isResubscribe = await Dialog.choice(
- () => lang.get("storeDowngradeOrResubscribe_msg", { "{AppStoreDowngrade}": InfoLink.AppStoreDowngrade }),
+ () => lang.get("storeDowngradeOrResubscribe_msg", { "{AppStoreDowngrade}": InfoLinks.AppStoreDowngrade }),
[
{
text: "changePlan_action",
@@ -333,7 +333,7 @@ export class PaymentViewer implements UpdatableSettingsViewer {
)
} else {
if (client.device == DeviceType.ANDROID) {
- return Dialog.message("invoiceFailedWebview_msg", () => m("div", m("a", { href: InfoLink.Webview, target: "_blank" }, InfoLink.Webview)))
+ return Dialog.message("invoiceFailedWebview_msg", () => m("div", m("a", { href: InfoLinks.Webview, target: "_blank" }, InfoLinks.Webview)))
} else if (client.isIos()) {
return Dialog.message("invoiceFailedIOS_msg")
} else {
@@ -537,7 +537,7 @@ function getPostingTypeText(posting: CustomerAccountPosting): string {
export async function showManageThroughAppStoreDialog(): Promise {
const confirmed = await Dialog.confirm(() =>
lang.get("storeSubscription_msg", {
- "{AppStorePayment}": InfoLink.AppStorePayment,
+ "{AppStorePayment}": InfoLinks.AppStorePayment,
}),
)
if (confirmed) {
diff --git a/src/common/subscription/SignupForm.ts b/src/common/subscription/SignupForm.ts
index 177391c547a1..7de565b0d130 100644
--- a/src/common/subscription/SignupForm.ts
+++ b/src/common/subscription/SignupForm.ts
@@ -18,7 +18,7 @@ import { Checkbox } from "../gui/base/Checkbox.js"
import type { lazy } from "@tutao/tutanota-utils"
import { getFirstOrThrow, ofClass } from "@tutao/tutanota-utils"
import type { TranslationKey } from "../misc/LanguageViewModel"
-import { InfoLink, lang } from "../misc/LanguageViewModel"
+import { InfoLinks, lang } from "../misc/LanguageViewModel"
import { showProgressDialog } from "../gui/dialogs/ProgressDialog"
import { InvalidDataError } from "../api/common/error/RestError"
import { locator } from "../api/main/CommonLocator"
@@ -187,7 +187,7 @@ export class SignupForm implements Component {
m(SelectMailAddressForm, mailAddressFormAttrs), // Leave as is
a.isPaidSubscription()
? m(".small.mt-s", lang.get("configureCustomDomainAfterSignup_msg"), [
- m(ExternalLink, { href: InfoLink.DomainInfo, isCompanySite: true }),
+ m(ExternalLink, { href: InfoLinks.DomainInfo, isCompanySite: true }),
])
: null,
m(PasswordForm, {
diff --git a/src/common/subscription/SubscriptionViewer.ts b/src/common/subscription/SubscriptionViewer.ts
index 0d6ec6f11391..e3f0973a8297 100644
--- a/src/common/subscription/SubscriptionViewer.ts
+++ b/src/common/subscription/SubscriptionViewer.ts
@@ -26,7 +26,7 @@ import {
UserTypeRef,
} from "../api/entities/sys/TypeRefs.js"
import { assertNotNull, base64ExtToBase64, base64ToUint8Array, downcast, incrementDate, neverNull, promiseMap } from "@tutao/tutanota-utils"
-import { InfoLink, lang, TranslationKey } from "../misc/LanguageViewModel"
+import { InfoLinks, lang, TranslationKey } from "../misc/LanguageViewModel"
import { Icons } from "../gui/base/icons/Icons"
import { asPaymentInterval, formatPrice, formatPriceDataWithInfo, PaymentInterval } from "./PriceUtils"
import { formatDate, formatStorageSize } from "../misc/Formatter"
@@ -291,7 +291,7 @@ export class SubscriptionViewer implements UpdatableSettingsViewer {
if (appStoreSubscriptionOwnership !== MobilePaymentSubscriptionOwnership.NoSubscription) {
return Dialog.message(() =>
lang.get("storeMultiSubscriptionError_msg", {
- "{AppStorePayment}": InfoLink.AppStorePayment,
+ "{AppStorePayment}": InfoLinks.AppStorePayment,
}),
)
}
@@ -323,7 +323,7 @@ export class SubscriptionViewer implements UpdatableSettingsViewer {
// There's a subscription with this apple account that doesn't belong to this user
return Dialog.message(() =>
lang.get("storeMultiSubscriptionError_msg", {
- "{AppStorePayment}": InfoLink.AppStorePayment,
+ "{AppStorePayment}": InfoLinks.AppStorePayment,
}),
)
} else if (
@@ -333,12 +333,12 @@ export class SubscriptionViewer implements UpdatableSettingsViewer {
) {
// User has an ongoing subscriptions but not on the current Apple Account, so we shouldn't allow them to change their plan with this account
// instead of the account owner of the subscriptions
- return Dialog.message(() => lang.get("storeNoSubscription_msg", { "{AppStorePayment}": InfoLink.AppStorePayment }))
+ return Dialog.message(() => lang.get("storeNoSubscription_msg", { "{AppStorePayment}": InfoLinks.AppStorePayment }))
} else if (appStoreSubscriptionOwnership === MobilePaymentSubscriptionOwnership.NoSubscription) {
// User has no ongoing subscription and isn't approved. We should allow them to downgrade their accounts or resubscribe and
// restart an Apple Subscription flow
const isResubscribe = await Dialog.choice(
- () => lang.get("storeDowngradeOrResubscribe_msg", { "{AppStoreDowngrade}": InfoLink.AppStoreDowngrade }),
+ () => lang.get("storeDowngradeOrResubscribe_msg", { "{AppStoreDowngrade}": InfoLinks.AppStoreDowngrade }),
[
{
text: "changePlan_action",
diff --git a/src/common/subscription/TermsAndConditions.ts b/src/common/subscription/TermsAndConditions.ts
index 4c35b0dc9331..50d14a524264 100644
--- a/src/common/subscription/TermsAndConditions.ts
+++ b/src/common/subscription/TermsAndConditions.ts
@@ -2,7 +2,7 @@
* The most recently published version of the terms and conditions
*/
import m, { Children } from "mithril"
-import { InfoLink, lang } from "../misc/LanguageViewModel"
+import { InfoLinks, lang } from "../misc/LanguageViewModel"
import { isApp } from "../api/common/Env"
import { requestFromWebsite } from "../misc/Website"
import { Dialog } from "../gui/base/Dialog"
@@ -29,15 +29,15 @@ export function renderTermsAndConditionsButton(terms: TermsSection, version: str
switch (terms) {
case TermsSection.GiftCards:
label = lang.get("giftCardTerms_label")
- link = InfoLink.GiftCardsTerms
+ link = InfoLinks.GiftCardsTerms
break
case TermsSection.Terms:
label = lang.get("termsAndConditionsLink_label")
- link = InfoLink.Terms
+ link = InfoLinks.Terms
break
case TermsSection.Privacy:
label = lang.get("privacyLink_label")
- link = InfoLink.Privacy
+ link = InfoLinks.Privacy
break
}
return m(
diff --git a/src/common/subscription/UpgradeSubscriptionWizard.ts b/src/common/subscription/UpgradeSubscriptionWizard.ts
index eb7a4cd8260f..09a243819ab0 100644
--- a/src/common/subscription/UpgradeSubscriptionWizard.ts
+++ b/src/common/subscription/UpgradeSubscriptionWizard.ts
@@ -15,7 +15,7 @@ import { getByAbbreviation } from "../api/common/CountryList"
import { UpgradeSubscriptionPage, UpgradeSubscriptionPageAttrs } from "./UpgradeSubscriptionPage"
import m from "mithril"
import stream from "mithril/stream"
-import { InfoLink, lang, TranslationKey, TranslationText } from "../misc/LanguageViewModel"
+import { InfoLinks, lang, TranslationKey, TranslationText } from "../misc/LanguageViewModel"
import { createWizardDialog, wizardPageWrapper } from "../gui/base/WizardDialog.js"
import { InvoiceAndPaymentDataPage, InvoiceAndPaymentDataPageAttrs } from "./InvoiceAndPaymentDataPage"
import { UpgradeCongratulationsPage, UpgradeCongratulationsPageAttrs } from "./UpgradeCongratulationsPage.js"
@@ -170,7 +170,7 @@ export async function loadSignupWizard(
}
message =
appstoreSubscriptionOwnership != MobilePaymentSubscriptionOwnership.NoSubscription
- ? () => lang.get("storeMultiSubscriptionError_msg", { "{AppStorePayment}": InfoLink.AppStorePayment })
+ ? () => lang.get("storeMultiSubscriptionError_msg", { "{AppStorePayment}": InfoLinks.AppStorePayment })
: null
} else {
message = null
diff --git a/src/common/support/FaqModel.ts b/src/common/support/FaqModel.ts
index 972b7c5a395f..ac4860866b55 100644
--- a/src/common/support/FaqModel.ts
+++ b/src/common/support/FaqModel.ts
@@ -4,6 +4,8 @@ import { delay, downcast, LazyLoaded } from "@tutao/tutanota-utils"
import { search } from "../api/common/utils/PlainTextSearch"
import { ProgrammingError } from "../api/common/error/ProgrammingError.js"
import { htmlSanitizer } from "../misc/HtmlSanitizer.js"
+import { locator } from "../api/main/CommonLocator.js"
+import { DomainConfigProvider } from "../api/common/DomainConfigProvider.js"
export type FaqEntry = {
id: string
@@ -45,13 +47,32 @@ export class FaqModel {
return Promise.all([this.fetchFAQ("en"), this.fetchFAQ(lang.code)]).then(([defaultTranslations, currentLanguageTranslations]) => {
if (defaultTranslations != null || currentLanguageTranslations != null) {
const faqLanguageViewModel = new LanguageViewModel()
- faqLanguageViewModel.initWithTranslations(lang.code, lang.languageTag, defaultTranslations, currentLanguageTranslations)
+ const isProd = this.websiteBaseUrl === "https://tuta.com"
+ faqLanguageViewModel.initWithTranslations(
+ lang.code,
+ lang.languageTag,
+ isProd ? defaultTranslations : this.replaceWebsiteUrls(defaultTranslations),
+ isProd ? defaultTranslations : this.replaceWebsiteUrls(currentLanguageTranslations),
+ )
this.faqLanguages = faqLanguageViewModel
}
})
})
}
+ // Replaces any instances of the production website in the faq entry with the correct stage (test, local etc.) of the website
+ private replaceWebsiteUrls(translation: Translation): Translation {
+ const filteredKeys: Record = Object.fromEntries(
+ Object.entries(translation.keys).map((entry) => {
+ const key = entry[0]
+ const value = entry[1].replaceAll("https://tuta.com", this.websiteBaseUrl)
+ return [key, value]
+ }),
+ )
+ // Expand translation to include extra fields, e.g. `name`
+ return { ...translation, code: translation.code, keys: filteredKeys }
+ }
+
async init(websiteBaseUrl: string): Promise {
//resetting the lazy reload whenever the language preference change to clear caching.
if (this.currentLanguageCode !== lang.code) {
diff --git a/src/common/termination/TerminationViewModel.ts b/src/common/termination/TerminationViewModel.ts
index 2a8d943f692e..d84aaef80a17 100644
--- a/src/common/termination/TerminationViewModel.ts
+++ b/src/common/termination/TerminationViewModel.ts
@@ -1,6 +1,6 @@
import { SessionType } from "../api/common/SessionType.js"
import { LoginState } from "../login/LoginViewModel.js"
-import { InfoLink, lang, TranslationText } from "../misc/LanguageViewModel.js"
+import { InfoLinks, lang, TranslationText } from "../misc/LanguageViewModel.js"
import { LoginController } from "../api/main/LoginController.js"
import { getLoginErrorStateAndMessage } from "../misc/LoginUtils.js"
import { SecondFactorHandler } from "../misc/2fa/SecondFactorHandler.js"
@@ -73,7 +73,7 @@ export class TerminationViewModel {
break
case "hasAppStoreSubscription":
this.onTerminationRequestFailed(() =>
- lang.get("deleteAccountWithAppStoreSubscription_msg", { "{AppStorePayment}": InfoLink.AppStorePayment }),
+ lang.get("deleteAccountWithAppStoreSubscription_msg", { "{AppStorePayment}": InfoLinks.AppStorePayment }),
)
break
default:
diff --git a/src/mail-app/app.ts b/src/mail-app/app.ts
index 3f25ef94b04d..2adf0bdcbb7b 100644
--- a/src/mail-app/app.ts
+++ b/src/mail-app/app.ts
@@ -1,7 +1,7 @@
import { client } from "../common/misc/ClientDetector.js"
import m from "mithril"
import Mithril, { Children, ClassComponent, Component, RouteDefs, RouteResolver, Vnode, VnodeDOM } from "mithril"
-import { lang, languageCodeToTag, languages } from "../common/misc/LanguageViewModel.js"
+import { lang, languageCodeToTag, languages, setInfoLinks } from "../common/misc/LanguageViewModel.js"
import { root } from "../RootView.js"
import { assertNotNull, neverNull } from "@tutao/tutanota-utils"
import { windowFacade } from "../common/misc/WindowFacade.js"
@@ -575,6 +575,8 @@ import("./translations/en.js")
const serviceworker = await import("../common/serviceworker/ServiceWorkerClient.js")
serviceworker.init(domainConfig)
+ setInfoLinks(domainConfig.websiteBaseUrl)
+
printJobsMessage(domainConfig)
})
diff --git a/src/mail-app/mail/editor/MailEditor.ts b/src/mail-app/mail/editor/MailEditor.ts
index b16e46897046..61bf4e76e8a6 100644
--- a/src/mail-app/mail/editor/MailEditor.ts
+++ b/src/mail-app/mail/editor/MailEditor.ts
@@ -4,7 +4,7 @@ import Stream from "mithril/stream"
import { Editor, ImagePasteEvent } from "../../../common/gui/editor/Editor"
import type { Attachment, InitAsResponseArgs, SendMailModel } from "../../../common/mailFunctionality/SendMailModel.js"
import { Dialog } from "../../../common/gui/base/Dialog"
-import { InfoLink, lang } from "../../../common/misc/LanguageViewModel"
+import { InfoLinks, lang } from "../../../common/misc/LanguageViewModel"
import type { MailboxDetail } from "../../../common/mailFunctionality/MailboxModel.js"
import { checkApprovalStatus } from "../../../common/misc/LoginUtils"
import { locator } from "../../../common/api/main/CommonLocator"
@@ -546,7 +546,7 @@ export class MailEditor implements Component {
return m(InfoBanner, {
message: "contentBlocked_msg",
icon: Icons.Picture,
- helpLink: canSeeTutaLinks(attrs.model.logins) ? InfoLink.LoadImages : null,
+ helpLink: canSeeTutaLinks(attrs.model.logins) ? InfoLinks.LoadImages : null,
buttons: [showButton],
})
}
diff --git a/src/mail-app/mail/signature/Signature.ts b/src/mail-app/mail/signature/Signature.ts
index 2dbb81a73a5e..6b6ed611ab3b 100644
--- a/src/mail-app/mail/signature/Signature.ts
+++ b/src/mail-app/mail/signature/Signature.ts
@@ -1,4 +1,4 @@
-import { InfoLink, lang } from "../../../common/misc/LanguageViewModel"
+import { InfoLinks, lang } from "../../../common/misc/LanguageViewModel"
import type { TutanotaProperties } from "../../../common/api/entities/tutanota/TypeRefs.js"
import { EmailSignatureType as TutanotaConstants } from "../../../common/api/common/TutanotaConstants"
import { htmlSanitizer } from "../../../common/misc/HtmlSanitizer"
@@ -14,7 +14,7 @@ export function getDefaultSignature(): string {
LINE_BREAK +
htmlSanitizer.sanitizeHTML(
lang.get("defaultEmailSignature_msg", {
- "{1}": `${InfoLink.HomePageFreeSignup}`,
+ "{1}": `${InfoLinks.HomePageFreeSignup}`,
}),
).html
)
diff --git a/src/mail-app/mail/view/MailViewerHeader.ts b/src/mail-app/mail/view/MailViewerHeader.ts
index 32524505404f..abee8ba87627 100644
--- a/src/mail-app/mail/view/MailViewerHeader.ts
+++ b/src/mail-app/mail/view/MailViewerHeader.ts
@@ -1,5 +1,5 @@
import m, { Children, Component, Vnode } from "mithril"
-import { InfoLink, lang } from "../../../common/misc/LanguageViewModel.js"
+import { InfoLinks, lang } from "../../../common/misc/LanguageViewModel.js"
import { theme } from "../../../common/gui/theme.js"
import { styles } from "../../../common/gui/styles.js"
import { ExpanderButton, ExpanderPanel } from "../../../common/gui/base/Expander.js"
@@ -610,7 +610,7 @@ export class MailViewerHeader implements Component {
message: "phishingMessageBody_msg",
icon: Icons.Warning,
type: BannerType.Warning,
- helpLink: canSeeTutaLinks(viewModel.logins) ? InfoLink.Phishing : null,
+ helpLink: canSeeTutaLinks(viewModel.logins) ? InfoLinks.Phishing : null,
buttons: [
{
label: "markAsNotPhishing_action",
@@ -629,7 +629,7 @@ export class MailViewerHeader implements Component {
return m(InfoBanner, {
message: "mailAuthFailed_msg",
icon: Icons.Warning,
- helpLink: canSeeTutaLinks(viewModel.logins) ? InfoLink.MailAuth : null,
+ helpLink: canSeeTutaLinks(viewModel.logins) ? InfoLinks.MailAuth : null,
type: BannerType.Warning,
buttons: [
{
@@ -651,7 +651,7 @@ export class MailViewerHeader implements Component {
})
: lang.get("mailAuthMissing_label"),
icon: Icons.Warning,
- helpLink: canSeeTutaLinks(viewModel.logins) ? InfoLink.MailAuth : null,
+ helpLink: canSeeTutaLinks(viewModel.logins) ? InfoLinks.MailAuth : null,
buttons: [
{
label: "close_alt",
@@ -704,7 +704,7 @@ export class MailViewerHeader implements Component {
return m(InfoBanner, {
message: "contentBlocked_msg",
icon: Icons.Picture,
- helpLink: canSeeTutaLinks(attrs.viewModel.logins) ? InfoLink.LoadImages : null,
+ helpLink: canSeeTutaLinks(attrs.viewModel.logins) ? InfoLinks.LoadImages : null,
buttons: [showButton, ...maybeDropdownButtons],
})
}
diff --git a/src/mail-app/mail/view/MailViewerUtils.ts b/src/mail-app/mail/view/MailViewerUtils.ts
index 6716f7d51654..0fb7d203966b 100644
--- a/src/mail-app/mail/view/MailViewerUtils.ts
+++ b/src/mail-app/mail/view/MailViewerUtils.ts
@@ -1,6 +1,6 @@
import { Keys, MailReportType, MailState, ReplyType, SYSTEM_GROUP_MAIL_ADDRESS } from "../../../common/api/common/TutanotaConstants"
import { assertNotNull, neverNull, ofClass } from "@tutao/tutanota-utils"
-import { InfoLink, lang } from "../../../common/misc/LanguageViewModel"
+import { InfoLinks, lang } from "../../../common/misc/LanguageViewModel"
import { Dialog } from "../../../common/gui/base/Dialog"
import m from "mithril"
import { Button, ButtonType } from "../../../common/gui/base/Button.js"
@@ -237,7 +237,7 @@ function reportMail(viewModel: MailViewerViewModel) {
},
[
m("div", lang.get("phishingReport_msg")),
- ifAllowedTutaLinks(locator.logins, InfoLink.Phishing, (link) =>
+ ifAllowedTutaLinks(locator.logins, InfoLinks.Phishing, (link) =>
m(ExternalLink, {
href: link,
text: lang.get("whatIsPhishing_msg"),
diff --git a/src/mail-app/settings/DesktopSettingsViewer.ts b/src/mail-app/settings/DesktopSettingsViewer.ts
index 767cbf62dfe7..7efd904046ed 100644
--- a/src/mail-app/settings/DesktopSettingsViewer.ts
+++ b/src/mail-app/settings/DesktopSettingsViewer.ts
@@ -1,5 +1,5 @@
import m, { Children } from "mithril"
-import { InfoLink, lang } from "../../common/misc/LanguageViewModel"
+import { InfoLinks, lang } from "../../common/misc/LanguageViewModel"
import stream from "mithril/stream"
import Stream from "mithril/stream"
import { showProgressDialog } from "../../common/gui/dialogs/ProgressDialog"
@@ -87,7 +87,7 @@ export class DesktopSettingsViewer implements UpdatableSettingsViewer {
const setRunInBackgroundAttrs: DropDownSelectorAttrs = {
label: "runInBackground_action",
helpLabel: () => {
- return ifAllowedTutaLinks(locator.logins, InfoLink.RunInBackground, (link) => [
+ return ifAllowedTutaLinks(locator.logins, InfoLinks.RunInBackground, (link) => [
m("span", lang.get("runInBackground_msg") + " "),
m(MoreInfoLink, { link: link }),
])
diff --git a/src/mail-app/settings/GlobalSettingsViewer.ts b/src/mail-app/settings/GlobalSettingsViewer.ts
index 03f8959476ad..d5ed86ce8487 100644
--- a/src/mail-app/settings/GlobalSettingsViewer.ts
+++ b/src/mail-app/settings/GlobalSettingsViewer.ts
@@ -1,6 +1,6 @@
import m, { Children } from "mithril"
import { DAY_IN_MILLIS, LazyLoaded, neverNull, noOp, ofClass, promiseMap } from "@tutao/tutanota-utils"
-import { InfoLink, lang } from "../../common/misc/LanguageViewModel"
+import { InfoLinks, lang } from "../../common/misc/LanguageViewModel"
import { getSpamRuleFieldToName, getSpamRuleTypeNameMapping, showAddSpamRuleDialog } from "./AddSpamRuleDialog"
import { getSpamRuleField, GroupType, OperationType, SpamRuleFieldType, SpamRuleType } from "../../common/api/common/TutanotaConstants"
import {
@@ -141,7 +141,7 @@ export class GlobalSettingsViewer implements UpdatableSettingsViewer {
title: "adminSpam_action",
table: spamRuleTableAttrs,
infoMsg: "adminSpamRuleInfo_msg",
- infoLinkId: InfoLink.SpamRules,
+ infoLinkId: InfoLinks.SpamRules,
}),
m(ExpandableTable, {
title: "rejectedEmails_label",
@@ -153,7 +153,7 @@ export class GlobalSettingsViewer implements UpdatableSettingsViewer {
title: "customEmailDomains_label",
table: customDomainTableAttrs,
infoMsg: "moreInfo_msg",
- infoLinkId: InfoLink.DomainInfo,
+ infoLinkId: InfoLinks.DomainInfo,
}),
m(AccountMaintenanceSettings, {
customerServerProperties: this.props,
diff --git a/src/mail-app/settings/emaildomain/VerifyDnsRecordsPage.ts b/src/mail-app/settings/emaildomain/VerifyDnsRecordsPage.ts
index 25dc432ac2e5..5f0bc339a0a4 100644
--- a/src/mail-app/settings/emaildomain/VerifyDnsRecordsPage.ts
+++ b/src/mail-app/settings/emaildomain/VerifyDnsRecordsPage.ts
@@ -1,7 +1,7 @@
import { DomainDnsStatus } from "../DomainDnsStatus"
import m, { Children, Vnode, VnodeDOM } from "mithril"
import { assertEnumValue, CustomDomainCheckResult, DnsRecordType, DnsRecordValidation } from "../../../common/api/common/TutanotaConstants"
-import { InfoLink, lang, TranslationKey } from "../../../common/misc/LanguageViewModel"
+import { InfoLinks, lang, TranslationKey } from "../../../common/misc/LanguageViewModel"
import type { AddDomainData, ValidatedDnSRecord } from "./AddDomainWizard"
import { Dialog } from "../../../common/gui/base/Dialog"
import type { WizardPageAttrs } from "../../../common/gui/base/WizardDialog.js"
@@ -187,7 +187,7 @@ export function renderCheckResult(domainStatus: DomainDnsStatus, hideRefreshButt
click: () => _updateDnsStatus(domainStatus),
},
),
- m(MoreInfoLink, { link: InfoLink.DomainInfo, class: "mt-m", isSmall: true }),
+ m(MoreInfoLink, { link: InfoLinks.DomainInfo, class: "mt-m", isSmall: true }),
]
} else {
const errorMessageMap: Record = {
diff --git a/src/mail-app/settings/groups/AddGroupDialog.ts b/src/mail-app/settings/groups/AddGroupDialog.ts
index 13d7c06c45b1..fe95106df1d3 100644
--- a/src/mail-app/settings/groups/AddGroupDialog.ts
+++ b/src/mail-app/settings/groups/AddGroupDialog.ts
@@ -5,7 +5,7 @@ import type { ValidationResult } from "../../../common/settings/SelectMailAddres
import { SelectMailAddressForm } from "../../../common/settings/SelectMailAddressForm.js"
import { getGroupTypeDisplayName } from "../../../common/settings/groups/GroupDetailsView.js"
import { showProgressDialog } from "../../../common/gui/dialogs/ProgressDialog.js"
-import { InfoLink, lang, TranslationKey } from "../../../common/misc/LanguageViewModel.js"
+import { InfoLinks, lang, TranslationKey } from "../../../common/misc/LanguageViewModel.js"
import { showBuyDialog } from "../../../common/subscription/BuyDialog.js"
import { PreconditionFailedError } from "../../../common/api/common/error/RestError.js"
import { showPlanUpgradeRequiredDialog } from "../../../common/misc/SubscriptionDialogs.js"
@@ -67,7 +67,7 @@ export class AddGroupDialog implements Component {
onDomainChanged,
}),
m(".mt-m", ""),
- m(MoreInfoLink, { link: InfoLink.SharedMailboxes, isSmall: true }),
+ m(MoreInfoLink, { link: InfoLinks.SharedMailboxes, isSmall: true }),
])
: m(""),
]
diff --git a/src/types.d.ts b/src/types.d.ts
index ebc8451f2681..79d8ba93bb65 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -57,7 +57,7 @@ type DomainConfig = {
giftCardBaseUrl: string
/** Which URL to use to build the referral URL. */
referralBaseUrl: string
- /** Base URL for requesting any information from de website */
+ /** Base URL for requesting any information from the website */
websiteBaseUrl: string
}
diff --git a/test/TestBuilder.js b/test/TestBuilder.js
index 399979ebc28f..a0483b3030a9 100644
--- a/test/TestBuilder.js
+++ b/test/TestBuilder.js
@@ -152,7 +152,7 @@ async function createUnitTestHtml(localEnv) {
console.log(`Generating browser tests at "${htmlFilePath}"`)
- const html = await renderHtml(imports, localEnv)
+ const html = await renderHtml(imports, localEnv, "local")
await writeFile(htmlFilePath, html)
}
diff --git a/test/tests/misc/news/items/ReferralLinkNewsTest.ts b/test/tests/misc/news/items/ReferralLinkNewsTest.ts
index a5d5213f9f35..60c1796cfe54 100644
--- a/test/tests/misc/news/items/ReferralLinkNewsTest.ts
+++ b/test/tests/misc/news/items/ReferralLinkNewsTest.ts
@@ -31,7 +31,7 @@ o.spec("ReferralLinkNews", function () {
u2fAppId: "https://app.test.tuta.com/u2f-appid.json",
giftCardBaseUrl: "https://app.test.tuta.com/giftcard",
referralBaseUrl: "https://app.test.tuta.com/signup",
- websiteBaseUrl: "https://tuta.com",
+ websiteBaseUrl: "https://test.tuta.com",
}
o.beforeEach(function () {