diff --git a/README.md b/README.md index 4582729d..1c9c46d8 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,7 @@ Grist can be configured in many ways. Here are the main environment variables it | GRIST_SINGLE_ORG | set to an org "domain" to pin client to that org | | GRIST_TEMPLATE_ORG | set to an org "domain" to show public docs from that org | | GRIST_HELP_CENTER | set the help center link ref | +| GRIST_TERMS_OF_SERVICE_URL | if set, adds terms of service link | | FREE_COACHING_CALL_URL | set the link to the human help (example: email adress or meeting scheduling tool) | | GRIST_CONTACT_SUPPORT_URL | set the link to contact support on error pages (example: email adress or online form) | | GRIST_SUPPORT_ANON | if set to 'true', show UI for anonymous access (not shown by default) | diff --git a/app/client/ui/HomeLeftPane.ts b/app/client/ui/HomeLeftPane.ts index e695345d..d30e6696 100644 --- a/app/client/ui/HomeLeftPane.ts +++ b/app/client/ui/HomeLeftPane.ts @@ -146,6 +146,14 @@ export function createHomeLeftPane(leftPanelOpen: Observable, home: Hom ) : null ), createHelpTools(home.app), + (commonUrls.termsOfService ? + cssPageEntry( + cssPageLink(cssPageIcon('Memo'), cssLinkText(t("Terms of service")), + { href: commonUrls.termsOfService, target: '_blank' }, + testId('dm-tos'), + ), + ) : null + ), ) ) ); diff --git a/app/common/gristUrls.ts b/app/common/gristUrls.ts index 431fd49e..ae7f8f4f 100644 --- a/app/common/gristUrls.ts +++ b/app/common/gristUrls.ts @@ -91,6 +91,7 @@ export const commonUrls = { helpAPI: 'https://support.getgrist.com/api', freeCoachingCall: getFreeCoachingCallUrl(), contactSupport: getContactSupportUrl(), + termsOfService: getTermsOfServiceUrl(), plans: "https://www.getgrist.com/pricing", sproutsProgram: "https://www.getgrist.com/sprouts-program", contact: "https://www.getgrist.com/contact", @@ -689,6 +690,9 @@ export interface GristLoadConfig { // Url for support for the browser client to use. helpCenterUrl?: string; + // Url for terms of service for the browser client to use + termsOfServiceUrl?: string; + // Url for free coaching call scheduling for the browser client to use. freeCoachingCallUrl?: string; @@ -900,6 +904,15 @@ export function getHelpCenterUrl(): string { } } +export function getTermsOfServiceUrl(): string|undefined { + if(isClient()) { + const gristConfig: GristLoadConfig = (window as any).gristConfig; + return gristConfig && gristConfig.termsOfServiceUrl || undefined; + } else { + return process.env.GRIST_TERMS_OF_SERVICE_URL || undefined; + } +} + export function getFreeCoachingCallUrl(): string { const defaultUrl = "https://calendly.com/grist-team/grist-free-coaching-call"; if(isClient()) { diff --git a/app/server/lib/sendAppPage.ts b/app/server/lib/sendAppPage.ts index 8c5ebf92..ec53f2be 100644 --- a/app/server/lib/sendAppPage.ts +++ b/app/server/lib/sendAppPage.ts @@ -4,6 +4,7 @@ import { getFreeCoachingCallUrl, getHelpCenterUrl, getPageTitleSuffix, + getTermsOfServiceUrl, GristLoadConfig, IFeature } from 'app/common/gristUrls'; @@ -62,6 +63,7 @@ export function makeGristConfig(options: MakeGristConfigOptions): GristLoadConfi baseDomain, singleOrg: process.env.GRIST_SINGLE_ORG, helpCenterUrl: getHelpCenterUrl(), + termsOfServiceUrl: getTermsOfServiceUrl(), freeCoachingCallUrl: getFreeCoachingCallUrl(), contactSupportUrl: getContactSupportUrl(), pathOnly, diff --git a/static/locales/fr.client.json b/static/locales/fr.client.json index cb42b57a..0a08458c 100644 --- a/static/locales/fr.client.json +++ b/static/locales/fr.client.json @@ -495,7 +495,8 @@ "Workspace will be moved to Trash.": "Le dossier va être mis à la corbeille.", "Manage Users": "Gérer les utilisateurs", "Access Details": "Détails d'accès", - "Tutorial": "Tutoriel" + "Tutorial": "Tutoriel", + "Terms of service": "CGU" }, "Importer": { "Update existing records": "Mettre à jour les enregistrements existants", diff --git a/test/nbrowser/TermsOfService.ts b/test/nbrowser/TermsOfService.ts new file mode 100644 index 00000000..21a021f6 --- /dev/null +++ b/test/nbrowser/TermsOfService.ts @@ -0,0 +1,37 @@ +import { assert, driver } from 'mocha-webdriver'; +import * as gu from 'test/nbrowser/gristUtils'; +import { server, setupTestSuite } from 'test/nbrowser/testUtils'; +import { EnvironmentSnapshot } from 'test/server/testUtils'; + +describe('Terms of service link', function () { + this.timeout(20000); + setupTestSuite({samples: true}); + + let session: gu.Session; + let oldEnv: EnvironmentSnapshot; + + before(async function () { + oldEnv = new EnvironmentSnapshot(); + session = await gu.session().teamSite.login(); + }); + + after(async function () { + oldEnv.restore(); + await server.restart(); + }); + + it('is visible in home menu', async function () { + process.env.GRIST_TERMS_OF_SERVICE_URL = 'https://example.com/tos'; + await server.restart(); + await session.loadDocMenu('/'); + assert.isTrue(await driver.find('.test-dm-tos').isDisplayed()); + assert.equal(await driver.find('.test-dm-tos').getAttribute('href'), 'https://example.com/tos'); + }); + + it('is not visible when environment variable is not set', async function () { + delete process.env.GRIST_TERMS_OF_SERVICE_URL; + await server.restart(); + await session.loadDocMenu('/'); + assert.isFalse(await driver.find('.test-dm-tos').isPresent()); + }); +});