diff --git a/frontend/src/metabase/admin/tasks/containers/Help.jsx b/frontend/src/metabase/admin/tasks/containers/Help.jsx index 67cbd89a2cb3ae9cb35aefbb8edc7dad59c0d3b8..940369b0030a22fce891170214e772c74d12715a 100644 --- a/frontend/src/metabase/admin/tasks/containers/Help.jsx +++ b/frontend/src/metabase/admin/tasks/containers/Help.jsx @@ -120,6 +120,13 @@ export default class Help extends Component { description={t`Create a GitHub issue (includes the diagnostic info below)`} link={githubIssueLink(detailString)} /> + {MetabaseSettings.isPaidPlan() && ( + <HelpLink + title={t`Contact support`} + description={t`Our team is ready to help you`} + link="mailto:support@metabase.com" + /> + )} </ol> </Box> diff --git a/frontend/src/metabase/icon_paths.js b/frontend/src/metabase/icon_paths.js index edb8723810558592247ea5ca38f84ed82d8d0fa0..6d8e5285eec70b6c0b086c7cd0f60cdafb000168 100644 --- a/frontend/src/metabase/icon_paths.js +++ b/frontend/src/metabase/icon_paths.js @@ -367,6 +367,11 @@ export const ICON_PATHS = { star: "M16 0 L21 11 L32 12 L23 19 L26 31 L16 25 L6 31 L9 19 L0 12 L11 11", star_outline: "M16 21.935l5.967 3.14-1.14-6.653 4.828-4.712-6.671-.97L16 6.685l-2.984 6.053-6.67.971 4.827 4.712-1.14 6.654L16 21.935zm-9.892 8.547l1.89-11.029L0 11.647l11.053-1.609L16 0l4.947 10.038L32 11.647l-7.997 7.806 1.889 11.03L16 25.274l-9.892 5.207z", + store: { + path: + "M4.537.091a.475.475 0 01.103.663L2.957 3.058a.475.475 0 11-.767-.56L3.873.193a.475.475 0 01.664-.103zM.031 5.018A.95.95 0 01.952 3.84h12.101a.95.95 0 01.921 1.178l-1.812 7.308a1.424 1.424 0 01-1.382 1.081H3.225a1.424 1.424 0 01-1.382-1.081L.031 5.018zM8.745.754a.475.475 0 11.767-.56l1.683 2.303a.475.475 0 11-.767.56L8.745.755z", + attrs: { viewBox: "0 0 15 14" }, + }, string: { path: "M14.022,18 L11.533,18 C11.2543319,18 11.0247509,17.935084 10.84425,17.80525 C10.6637491,17.675416 10.538667,17.5091677 10.469,17.3065 L9.652,14.8935 L4.389,14.8935 L3.572,17.3065 C3.50866635,17.4838342 3.38516758,17.6437493 3.2015,17.78625 C3.01783241,17.9287507 2.79300133,18 2.527,18 L0.019,18 L5.377,4.1585 L8.664,4.1585 L14.022,18 Z M5.13,12.7085 L8.911,12.7085 L7.638,8.918 C7.55566626,8.67733213 7.45908389,8.3939183 7.34825,8.06775 C7.23741611,7.7415817 7.12816721,7.3885019 7.0205,7.0085 C6.91916616,7.39483527 6.8146672,7.75266502 6.707,8.082 C6.5993328,8.41133498 6.49800047,8.69633213 6.403,8.937 L5.13,12.7085 Z M21.945,18 C21.6663319,18 21.4557507,17.9620004 21.31325,17.886 C21.1707493,17.8099996 21.0520005,17.6516679 20.957,17.411 L20.748,16.8695 C20.5009988,17.078501 20.2635011,17.2621659 20.0355,17.4205 C19.8074989,17.5788341 19.5715846,17.7134161 19.32775,17.82425 C19.0839154,17.9350839 18.8242514,18.0174164 18.54875,18.07125 C18.2732486,18.1250836 17.9676683,18.152 17.632,18.152 C17.1823311,18.152 16.7738352,18.0934173 16.4065,17.97625 C16.0391648,17.8590827 15.7272513,17.6865011 15.47075,17.4585 C15.2142487,17.2304989 15.016334,16.947085 14.877,16.60825 C14.737666,16.269415 14.668,15.8783355 14.668,15.435 C14.668,15.0866649 14.7566658,14.7288352 14.934,14.3615 C15.1113342,13.9941648 15.4184978,13.6600848 15.8555,13.35925 C16.2925022,13.0584152 16.8814963,12.8066677 17.6225,12.604 C18.3635037,12.4013323 19.297661,12.2873335 20.425,12.262 L20.425,11.844 C20.425,11.2676638 20.3062512,10.8512513 20.06875,10.59475 C19.8312488,10.3382487 19.4940022,10.21 19.057,10.21 C18.7086649,10.21 18.4236678,10.2479996 18.202,10.324 C17.9803322,10.4000004 17.7824175,10.4854995 17.60825,10.5805 C17.4340825,10.6755005 17.2646675,10.7609996 17.1,10.837 C16.9353325,10.9130004 16.7390011,10.951 16.511,10.951 C16.3083323,10.951 16.1357507,10.9019172 15.99325,10.80375 C15.8507493,10.7055828 15.7383337,10.5836674 15.656,10.438 L15.124,9.5165 C15.7193363,8.99083071 16.3795797,8.59975128 17.10475,8.34325 C17.8299203,8.08674872 18.6073292,7.9585 19.437,7.9585 C20.0323363,7.9585 20.5690809,8.05508237 21.04725,8.24825 C21.5254191,8.44141763 21.9307483,8.71058161 22.26325,9.05575 C22.5957517,9.40091839 22.8506658,9.81099763 23.028,10.286 C23.2053342,10.7610024 23.294,11.2803305 23.294,11.844 L23.294,18 L21.945,18 Z M18.563,16.2045 C18.9430019,16.2045 19.2754986,16.1380007 19.5605,16.005 C19.8455014,15.8719993 20.1336652,15.6566682 20.425,15.359 L20.425,13.991 C19.8359971,14.0163335 19.3515019,14.0669996 18.9715,14.143 C18.5914981,14.2190004 18.2906678,14.3139994 18.069,14.428 C17.8473322,14.5420006 17.6937504,14.6718326 17.60825,14.8175 C17.5227496,14.9631674 17.48,15.1214991 17.48,15.2925 C17.48,15.6281683 17.5718324,15.8640827 17.7555,16.00025 C17.9391676,16.1364173 18.2083316,16.2045 18.563,16.2045 L18.563,16.2045 Z", diff --git a/frontend/src/metabase/lib/settings.js b/frontend/src/metabase/lib/settings.js index 0433689373b902efd08804c45413c93d2d34dcce..db187148056f5ea03e7bae5a0807457896d622cc 100644 --- a/frontend/src/metabase/lib/settings.js +++ b/frontend/src/metabase/lib/settings.js @@ -210,6 +210,10 @@ class Settings { return false; } + isPaidPlan() { + return this.isHosted() || this.isEnterprise(); + } + // returns a map that looks like {total: 6, digit: 1} passwordComplexityRequirements() { return this.get("password-complexity", {}); diff --git a/frontend/src/metabase/nav/components/StoreLink/StoreLink.jsx b/frontend/src/metabase/nav/components/StoreLink/StoreLink.jsx new file mode 100644 index 0000000000000000000000000000000000000000..2ee83e41a98cfb6acbeb1399f58dba7eadf1d3cc --- /dev/null +++ b/frontend/src/metabase/nav/components/StoreLink/StoreLink.jsx @@ -0,0 +1,18 @@ +import React from "react"; +import { t } from "ttag"; +import Tooltip from "metabase/components/Tooltip"; +import { StoreIcon, StoreIconRoot, StoreIconWrapper } from "./StoreLink.styled"; + +const StoreLink = () => { + return ( + <Tooltip tooltip={t`Explore paid features`}> + <StoreIconRoot href="https://metabase.com/upgrade"> + <StoreIconWrapper> + <StoreIcon /> + </StoreIconWrapper> + </StoreIconRoot> + </Tooltip> + ); +}; + +export default StoreLink; diff --git a/frontend/src/metabase/nav/components/StoreLink/StoreLink.styled.jsx b/frontend/src/metabase/nav/components/StoreLink/StoreLink.styled.jsx new file mode 100644 index 0000000000000000000000000000000000000000..8df56a95afca4d957db9463e2fc9aa57658c1fd6 --- /dev/null +++ b/frontend/src/metabase/nav/components/StoreLink/StoreLink.styled.jsx @@ -0,0 +1,25 @@ +import styled from "styled-components"; +import { color, darken } from "metabase/lib/colors"; +import { space } from "metabase/styled-components/theme"; +import Icon, { IconWrapper } from "metabase/components/Icon"; +import ExternalLink from "metabase/components/ExternalLink"; + +export const StoreIconRoot = styled(ExternalLink)` + margin-right: ${space(1)}; +`; + +export const StoreIconWrapper = styled(IconWrapper)` + color: ${color("white")}; + + &:hover { + color: ${color("white")}; + background-color: ${darken(color("accent7"))}; + } +`; + +export const StoreIcon = styled(Icon).attrs({ + name: "store", + size: 18, +})` + margin: ${space(1)}; +`; diff --git a/frontend/src/metabase/nav/components/StoreLink/index.js b/frontend/src/metabase/nav/components/StoreLink/index.js new file mode 100644 index 0000000000000000000000000000000000000000..59ef9cb93dbfaf2e61a00138ff0551afa6d9a538 --- /dev/null +++ b/frontend/src/metabase/nav/components/StoreLink/index.js @@ -0,0 +1 @@ +export { default } from "./StoreLink"; diff --git a/frontend/src/metabase/nav/containers/Navbar.jsx b/frontend/src/metabase/nav/containers/Navbar.jsx index f9073dbb89d0485dd33280ee4bb6ec0c3bb0cf49..a42856c544cc50c3d9af9c9467f90e3fd427e2cd 100644 --- a/frontend/src/metabase/nav/containers/Navbar.jsx +++ b/frontend/src/metabase/nav/containers/Navbar.jsx @@ -13,6 +13,7 @@ import { Flex, Box } from "grid-styled"; import * as Urls from "metabase/lib/urls"; import { color, darken } from "metabase/lib/colors"; +import MetabaseSettings from "metabase/lib/settings"; import Icon, { IconWrapper } from "metabase/components/Icon"; import EntityMenu from "metabase/components/EntityMenu"; @@ -43,6 +44,7 @@ const mapStateToProps = (state, props) => ({ }); import { DefaultSearchColor } from "metabase/nav/constants"; +import StoreLink from "metabase/nav/components/StoreLink"; const mapDispatchToProps = { onChangeLocation: push, @@ -156,6 +158,7 @@ export default class Navbar extends Component { /> </ul> + {!MetabaseSettings.isPaidPlan() && <StoreLink />} <ProfileLink {...this.props} /> </div> {this.renderModal()} diff --git a/frontend/test/__support__/e2e/cypress.js b/frontend/test/__support__/e2e/cypress.js index c08724421a017f51ab6ca2ad05fe07242144ed1e..c0b3f2c43725d221f01789f73488ccabea49569c 100644 --- a/frontend/test/__support__/e2e/cypress.js +++ b/frontend/test/__support__/e2e/cypress.js @@ -18,6 +18,7 @@ export * from "./helpers/e2e-ad-hoc-question-helpers"; export * from "./helpers/e2e-enterprise-helpers"; export * from "./helpers/e2e-mock-app-settings-helpers"; export * from "./helpers/e2e-assertion-helpers"; +export * from "./helpers/e2e-cloud-helpers"; export * from "./helpers/e2e-data-model-helpers"; export * from "./helpers/e2e-misc-helpers"; export * from "./helpers/e2e-deprecated-helpers"; diff --git a/frontend/test/__support__/e2e/helpers/e2e-cloud-helpers.js b/frontend/test/__support__/e2e/helpers/e2e-cloud-helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..193fb9a47460d06cc8155beb32c10ebf4dab1e60 --- /dev/null +++ b/frontend/test/__support__/e2e/helpers/e2e-cloud-helpers.js @@ -0,0 +1,5 @@ +export const setupMetabaseCloud = () => { + cy.request("PUT", "/api/setting/site-url", { + value: "https://CYPRESSTESTENVIRONMENT.metabaseapp.com", + }); +}; diff --git a/frontend/test/metabase/scenarios/admin/settings/cloud.cy.spec.js b/frontend/test/metabase/scenarios/admin/settings/cloud.cy.spec.js index 411432b34e3e1aa0a8bd9fad91c5a076da36a4dc..5f0db774cacddfafa3b4415f28181a38ce4d172d 100644 --- a/frontend/test/metabase/scenarios/admin/settings/cloud.cy.spec.js +++ b/frontend/test/metabase/scenarios/admin/settings/cloud.cy.spec.js @@ -1,4 +1,4 @@ -import { restore } from "__support__/e2e/cypress"; +import { restore, setupMetabaseCloud } from "__support__/e2e/cypress"; describe("Cloud settings section", () => { beforeEach(() => { @@ -29,9 +29,3 @@ describe("Cloud settings section", () => { cy.findByText(/Cloud Settings/i).should("not.exist"); }); }); - -function setupMetabaseCloud() { - cy.request("PUT", "/api/setting/site-url", { - value: "https://CYPRESSTESTENVIRONMENT.metabaseapp.com", - }); -} diff --git a/frontend/test/metabase/scenarios/admin/settings/settings.cy.spec.js b/frontend/test/metabase/scenarios/admin/settings/settings.cy.spec.js index d2274a8ca4d75029dfd82e74b9ba05995036d84c..8302b1e1d4e898807950090c35cb9e4603a9ebb9 100644 --- a/frontend/test/metabase/scenarios/admin/settings/settings.cy.spec.js +++ b/frontend/test/metabase/scenarios/admin/settings/settings.cy.spec.js @@ -4,6 +4,8 @@ import { version, popover, describeWithToken, + setupMetabaseCloud, + describeWithoutToken, } from "__support__/e2e/cypress"; import { SAMPLE_DATASET } from "__support__/e2e/cypress_sample_dataset"; @@ -368,14 +370,12 @@ describe("scenarios > admin > settings", () => { cy.findByText("Updates").should("not.exist"); }); - describeWithToken("EE", () => { - it("should hide Enterprise settings when running Metabase Cloud", () => { - setupMetabaseCloud(); - cy.visit("/admin/settings/general"); + it("should hide the store link when running Metabase Cloud", () => { + setupMetabaseCloud(); + cy.visit("/admin/settings/general"); - cy.findByText("Site Name"); - cy.findByText("Enterprise").should("not.exist"); - }); + cy.findByText("Metabase Admin"); + cy.findByLabelText("store icon").should("not.exist"); }); describe(" > slack settings", () => { @@ -391,15 +391,45 @@ describe("scenarios > admin > settings", () => { }); }); +describeWithoutToken("scenarios > admin > settings (OSS)", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + }); + + it("should show the store link when running Metabase OSS", () => { + cy.visit("/admin/settings/general"); + + cy.findByText("Metabase Admin"); + cy.findByLabelText("store icon"); + }); +}); + +describeWithToken("scenarios > admin > settings (EE)", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + }); + + it("should hide Enterprise page when running Metabase Cloud", () => { + setupMetabaseCloud(); + cy.visit("/admin/settings/general"); + + cy.findByText("Site Name"); + cy.findByText("Enterprise").should("not.exist"); + }); + + it("should hide the store link when running Metabase EE", () => { + cy.visit("/admin/settings/general"); + + cy.findByText("Metabase Admin"); + cy.findByLabelText("store icon").should("not.exist"); + }); +}); + function configureAuth(providerTitle) { cy.findByText(providerTitle) .closest(".rounded.bordered") .contains("Configure") .click(); } - -function setupMetabaseCloud() { - cy.request("PUT", "/api/setting/site-url", { - value: "https://CYPRESSTESTENVIRONMENT.metabaseapp.com", - }); -} diff --git a/frontend/test/metabase/scenarios/admin/troubleshooting/help.cy.spec.js b/frontend/test/metabase/scenarios/admin/troubleshooting/help.cy.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..0ec2930e023163b1d026f2029bbc88d43d68abd2 --- /dev/null +++ b/frontend/test/metabase/scenarios/admin/troubleshooting/help.cy.spec.js @@ -0,0 +1,49 @@ +import { + describeWithoutToken, + describeWithToken, + restore, + setupMetabaseCloud, +} from "__support__/e2e/cypress"; + +describe("scenarios > admin > troubleshooting > help", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + }); + + it("should add the support link when running Metabase Cloud", () => { + setupMetabaseCloud(); + cy.visit("/admin/troubleshooting/help"); + + cy.findByText("Metabase Admin"); + cy.findByText("Contact support"); + }); +}); + +describeWithoutToken("scenarios > admin > troubleshooting > help", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + }); + + it("should hide the support link when running Metabase OSS", () => { + cy.visit("/admin/troubleshooting/help"); + + cy.findByText("Metabase Admin"); + cy.findByText("Contact support").should("not.exist"); + }); +}); + +describeWithToken("scenarios > admin > troubleshooting > help (EE)", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + }); + + it("should add the support link when running Metabase EE", () => { + cy.visit("/admin/troubleshooting/help"); + + cy.findByText("Metabase Admin"); + cy.findByText("Contact support"); + }); +});