diff --git a/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/SettingsCloudStoreLink.jsx b/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/SettingsCloudStoreLink.jsx new file mode 100644 index 0000000000000000000000000000000000000000..5cc2230510c501e1ea9351265bc3697cb1ec9565 --- /dev/null +++ b/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/SettingsCloudStoreLink.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import { t } from "ttag"; +import MetabaseSettings from "metabase/lib/settings"; +import { Description, Link, LinkIcon } from "./SettingsCloudStoreLink.styled"; + +export function SettingsCloudStoreLink() { + const url = MetabaseSettings.storeUrl(); + return ( + <div> + <Description>{t`Manage your Cloud account, including billing preferences and technical settings about this instance in your Metabase Store account.`}</Description> + <Link href={url}> + {t`Go to the Metabase Store`} + <LinkIcon name="external" /> + </Link> + </div> + ); +} diff --git a/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/SettingsCloudStoreLink.styled.js b/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/SettingsCloudStoreLink.styled.js new file mode 100644 index 0000000000000000000000000000000000000000..0952a5b9ebd4e77fc68316f6c8d3e8d13fd100e1 --- /dev/null +++ b/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/SettingsCloudStoreLink.styled.js @@ -0,0 +1,30 @@ +import styled from "styled-components"; +import { color } from "metabase/lib/colors"; +import ExternalLink from "metabase/components/ExternalLink"; +import Icon from "metabase/components/Icon"; + +export const Description = styled.p` + color: ${color("text-dark")}; + max-width: 360px; +`; + +export const Link = styled(ExternalLink)` + display: inline-flex; + align-items: center; + color: ${color("text-white")}; + font-weight: bold; + background-color: ${color("brand")}; + padding: 12px 18px; + border-radius: 6px; + + &:hover { + opacity: 0.88; + transition: all 200ms linear; + } +`; + +export const LinkIcon = styled(Icon)` + color: ${color("text-white")}; + opacity: 0.6; + margin-left: 8px; +`; diff --git a/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/index.js b/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/index.js new file mode 100644 index 0000000000000000000000000000000000000000..6ae42da6388f3aee5f8fb7040ebaeea3fa95f93e --- /dev/null +++ b/frontend/src/metabase/admin/settings/components/SettingsCloudStoreLink/index.js @@ -0,0 +1 @@ +export * from "./SettingsCloudStoreLink"; diff --git a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingLevel.jsx b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingLevel.jsx index be075ba2bd3c064a6b26ec0193676c9f778e6739..fccae6071fb9644f355c4cdcba8798bcac248fda 100644 --- a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingLevel.jsx +++ b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingLevel.jsx @@ -5,9 +5,11 @@ import SettingsInput from "./SettingInput"; import cx from "classnames"; import ExternalLink from "metabase/components/ExternalLink"; +import MetabaseSettings from "metabase/lib/settings"; -const PREMIUM_EMBEDDING_STORE_URL = - "https://store.metabase.com/product/embedding"; +const PREMIUM_EMBEDDING_STORE_URL = MetabaseSettings.storeUrl( + "product/embedding", +); const PREMIUM_EMBEDDING_SETTING_KEY = "premium-embedding-token"; class PremiumTokenInput extends Component { diff --git a/frontend/src/metabase/admin/settings/selectors.js b/frontend/src/metabase/admin/settings/selectors.js index 428434ce2625de71b9fafbbe3c8c8d57b51daa32..1304b1f61a33a9fa6d22eab02f8de46947cea972 100644 --- a/frontend/src/metabase/admin/settings/selectors.js +++ b/frontend/src/metabase/admin/settings/selectors.js @@ -16,6 +16,7 @@ import EmbeddingLegalese from "./components/widgets/EmbeddingLegalese"; import EmbeddingLevel from "./components/widgets/EmbeddingLevel"; import FormattingWidget from "./components/widgets/FormattingWidget"; +import { SettingsCloudStoreLink } from "./components/SettingsCloudStoreLink"; import SettingsUpdatesForm from "./components/SettingsUpdatesForm/SettingsUpdatesForm"; import SettingsEmailForm from "./components/SettingsEmailForm"; import SettingsSetupList from "./components/SettingsSetupList"; @@ -392,6 +393,22 @@ const SECTIONS = updateSectionsWithPlugins({ }, }); +if (MetabaseSettings.isHosted()) { + const allSections = Object.values(SECTIONS); + const lastSection = _.max(allSections, "order"); + SECTIONS.cloud = { + name: t`Cloud`, + order: lastSection.order + 1, + settings: [ + { + key: "store-link", + display_name: t`Cloud Settings`, + widget: SettingsCloudStoreLink, + }, + ], + }; +} + export const getSettings = createSelector( state => state.admin.settings.settings, state => state.admin.settings.warnings, diff --git a/frontend/src/metabase/lib/settings.js b/frontend/src/metabase/lib/settings.js index 2e5315f184bd7179229ab4ec3d128b75dd2c1c91..0433689373b902efd08804c45413c93d2d34dcce 100644 --- a/frontend/src/metabase/lib/settings.js +++ b/frontend/src/metabase/lib/settings.js @@ -157,6 +157,10 @@ class Settings { return `https://www.metabase.com/docs/${tag}/${page}${anchor}`; } + storeUrl(path = "") { + return `https://store.metabase.com/${path}`; + } + newVersionAvailable() { const result = MetabaseUtils.compareVersions( this.currentVersion(), diff --git a/frontend/src/metabase/nav/components/ProfileLink.jsx b/frontend/src/metabase/nav/components/ProfileLink.jsx index f99982eb546824aa894cd6941f729ba44826fecf..e2370bea3961d8017dd56d64cfc3275e88619d0a 100644 --- a/frontend/src/metabase/nav/components/ProfileLink.jsx +++ b/frontend/src/metabase/nav/components/ProfileLink.jsx @@ -49,7 +49,7 @@ export default class ProfileLink extends Component { admin && [ { title: t`Manage Metabase Cloud`, - link: "https://store.metabase.com/login", + link: MetabaseSettings.storeUrl("login"), event: `Navbar;Profile Dropdown;ManageHosting ${tag}`, externalLink: true, }, diff --git a/frontend/test/metabase/scenarios/admin/settings/cloud.cy.spec.js b/frontend/test/metabase/scenarios/admin/settings/cloud.cy.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..411432b34e3e1aa0a8bd9fad91c5a076da36a4dc --- /dev/null +++ b/frontend/test/metabase/scenarios/admin/settings/cloud.cy.spec.js @@ -0,0 +1,37 @@ +import { restore } from "__support__/e2e/cypress"; + +describe("Cloud settings section", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + }); + + it("should be visible when running Metabase Cloud", () => { + setupMetabaseCloud(); + cy.visit("/admin"); + cy.get(".AdminList-items") + .findByText("Cloud") + .click(); + cy.findByText(/Cloud Settings/i); + cy.findByText("Go to the Metabase Store").should( + "have.attr", + "href", + "https://store.metabase.com/", + ); + }); + + it("should be invisible when self-hosting", () => { + cy.visit("/admin"); + cy.get(".AdminList-items") + .findByText("Cloud") + .should("not.exist"); + cy.visit("/admin/settings/cloud"); + cy.findByText(/Cloud Settings/i).should("not.exist"); + }); +}); + +function setupMetabaseCloud() { + cy.request("PUT", "/api/setting/site-url", { + value: "https://CYPRESSTESTENVIRONMENT.metabaseapp.com", + }); +}