diff --git a/frontend/src/metabase-types/api/mocks/settings.ts b/frontend/src/metabase-types/api/mocks/settings.ts index e561d9aa800ddf2589725a5ee32e42008f7f3189..07f4f8e1da2730da2d91eeb4199af4ebb8597a0d 100644 --- a/frontend/src/metabase-types/api/mocks/settings.ts +++ b/frontend/src/metabase-types/api/mocks/settings.ts @@ -22,6 +22,7 @@ export const createMockSettings = (opts?: Partial<Settings>): Settings => ({ "enable-public-sharing": false, "enable-xrays": false, engines: createMockEngines(), + "is-hosted?": false, "deprecation-notice-version": undefined, "show-database-syncing-modal": false, "show-homepage-data": false, diff --git a/frontend/src/metabase-types/api/settings.ts b/frontend/src/metabase-types/api/settings.ts index 199b809ec5fa711f699c74af124afdaca234b593..418160e02aecfcd3221a0af8483d90c5e40f5553 100644 --- a/frontend/src/metabase-types/api/settings.ts +++ b/frontend/src/metabase-types/api/settings.ts @@ -11,6 +11,7 @@ export interface Settings { "enable-public-sharing": boolean; "enable-xrays": boolean; engines: Record<string, Engine>; + "is-hosted?": boolean; "deprecation-notice-version": string | undefined; "show-database-syncing-modal": boolean; "show-homepage-data": boolean; diff --git a/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx index 45f19940e92c3bc0314b2a4e304761ee555705f0..84b0948f81746281d5704ffa84b7668673b58112 100644 --- a/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx +++ b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.jsx @@ -11,7 +11,6 @@ import { Box, Flex } from "grid-styled"; import title from "metabase/hoc/Title"; -import AddDatabaseHelpCard from "metabase/components/AddDatabaseHelpCard"; import Button from "metabase/components/Button"; import Breadcrumbs from "metabase/components/Breadcrumbs"; import Sidebar from "metabase/admin/databases/components/DatabaseEditApp/Sidebar/Sidebar"; @@ -36,6 +35,7 @@ import { selectEngine, } from "../database"; import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper"; +import { HelpCard } from "./DatabaseEditApp.styled"; const DATABASE_FORM_NAME = "database"; @@ -162,11 +162,7 @@ export default class DatabaseEditApp extends Component { </Box> <Box> {addingNewDatabase && ( - <AddDatabaseHelpCard - engine={selectedEngine} - ml={26} - data-testid="database-setup-help-card" - /> + <HelpCard engine={selectedEngine} /> )} </Box> </Flex> diff --git a/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.styled.tsx b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.styled.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b69e5da807591731d24aa6648e77fcc122524a64 --- /dev/null +++ b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.styled.tsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; +import DatabaseHelpCard from "metabase/containers/DatabaseHelpCard"; + +export const HelpCard = styled(DatabaseHelpCard)` + max-width: 21rem; + margin-top: 1.25rem; + margin-left: 6.5rem; +`; diff --git a/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.unit.spec.js b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.unit.spec.js index 8f802c436de057c0627353afa4148906c2221d55..1fe838c2ef37f33510f9d2fc85a855d2fa71c6ef 100644 --- a/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.unit.spec.js +++ b/frontend/src/metabase/admin/databases/containers/DatabaseEditApp.unit.spec.js @@ -29,6 +29,7 @@ const ENGINES_MOCK = { }; const ComponentMock = () => <div />; +jest.mock("metabase/containers/DatabaseHelpCard", () => ComponentMock); jest.mock("metabase/containers/DriverWarning", () => ComponentMock); function mockSettings({ cachingEnabled = false }) { diff --git a/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.stories.tsx b/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.stories.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2213f5c2830c757a3c6433e03d2fda5de932d8b3 --- /dev/null +++ b/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.stories.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import { ComponentStory } from "@storybook/react"; +import SlackHelpCard from "./SlackHelpCard"; + +export default { + title: "Admin/Settings/Slack/SlackHelpCard", + component: SlackHelpCard, +}; + +const Template: ComponentStory<typeof SlackHelpCard> = args => { + return <SlackHelpCard {...args} />; +}; + +export const Default = Template.bind({}); diff --git a/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.styled.tsx b/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.styled.tsx index 1946d1025939fcdaaae919ad94cb46c7c14fca11..d7ba0a88ccd48d8f30082741070ec97f55d06872 100644 --- a/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.styled.tsx +++ b/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.styled.tsx @@ -6,9 +6,14 @@ import ExternalLink from "metabase/components/ExternalLink"; export const CardRoot = styled(ExternalLink)` display: block; padding: 1.5rem; + border: 1px solid ${color("border")}; border-radius: 0.375rem; background-color: ${color("white")}; box-shadow: 0 1px 6px ${color("shadow")}; + + &:hover { + background-color: ${color("bg-light")}; + } `; export const CardHeader = styled.span` diff --git a/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.tsx b/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.tsx index 8e88c5993fc1800b63241996d80ecc8304f8937e..6b9f83a1ed5e666f94e20719b7e394d73fb96d31 100644 --- a/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.tsx +++ b/frontend/src/metabase/admin/settings/slack/components/SlackHelpCard/SlackHelpCard.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from "react"; +import React from "react"; import { t } from "ttag"; import Settings from "metabase/lib/settings"; import { @@ -14,10 +14,7 @@ export interface SlackHelpCardProps { } const SlackHelpCard = ({ className }: SlackHelpCardProps): JSX.Element => { - const docsUrl = useMemo( - () => Settings.docsUrl("administration-guide/09-setting-up-slack"), - [], - ); + const docsUrl = Settings.docsUrl("administration-guide/09-setting-up-slack"); return ( <CardRoot className={className} href={docsUrl}> diff --git a/frontend/src/metabase/components/AddDatabaseHelpCard.jsx b/frontend/src/metabase/components/AddDatabaseHelpCard.jsx deleted file mode 100644 index afadd51a96a3d266f23742f1c3a75d337ee75276..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/components/AddDatabaseHelpCard.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import React from "react"; -import PropTypes from "prop-types"; - -import { t, jt } from "ttag"; - -import MetabaseSettings from "metabase/lib/settings"; - -import ExternalLink from "metabase/components/ExternalLink"; -import Icon from "metabase/components/Icon"; - -import { - CardContent, - HelpCardContainer, - IconContainer, -} from "./AddDatabaseHelpCard.styled"; - -export const ENGINE_DOCS = { - bigquery: MetabaseSettings.docsUrl("administration-guide/databases/bigquery"), - mongo: MetabaseSettings.docsUrl("administration-guide/databases/mongodb"), - mysql: MetabaseSettings.docsUrl("administration-guide/databases/mysql"), - oracle: MetabaseSettings.docsUrl("administration-guide/databases/oracle"), - snowflake: MetabaseSettings.docsUrl( - "administration-guide/databases/snowflake", - ), - vertica: MetabaseSettings.docsUrl("administration-guide/databases/vertica"), -}; - -export const GENERAL_DB_DOC = MetabaseSettings.docsUrl( - "administration-guide/01-managing-databases", -); - -export const CLOUD_HELP_URL = "https://www.metabase.com/help/cloud"; - -const propTypes = { - engine: PropTypes.string, - hasCircle: PropTypes.bool, -}; - -function AddDatabaseHelpCard({ engine, hasCircle = true, ...props }) { - const docsLink = ENGINE_DOCS[engine] || GENERAL_DB_DOC; - const hasDocLink = ENGINE_DOCS[engine] != null; - const shouldDisplayHelpLink = MetabaseSettings.isHosted(); - - const engines = MetabaseSettings.get("engines", {}); - const engineInfo = engines[engine] || {}; - const displayName = hasDocLink ? engineInfo["driver-name"] : t`your database`; - const supersededBy = engineInfo["superseded-by"]; - - if (supersededBy) { - return null; - } - - return ( - <HelpCardContainer p={2} {...props}> - <IconContainer - align="center" - justify="center" - className="flex-no-shrink circular" - hasCircle={hasCircle} - > - <Icon size={20} name="database" className="text-brand" /> - </IconContainer> - <CardContent - flexDirection="column" - justify="center" - className="ml2" - shouldDisplayHelpLink={shouldDisplayHelpLink} - > - <div> - <p className="text-medium m0"> - {t`Need help setting up`} {displayName}? - </p> - <ExternalLink href={docsLink} className="text-brand text-bold"> - {t`Our docs can help.`} - </ExternalLink> - </div> - {shouldDisplayHelpLink && ( - <p className="mt2 text-medium m0"> - {jt`Docs weren't enough?`}{" "} - <ExternalLink - href={CLOUD_HELP_URL} - className="text-brand text-bold" - > - {t`Write us.`} - </ExternalLink> - </p> - )} - </CardContent> - </HelpCardContainer> - ); -} - -AddDatabaseHelpCard.propTypes = propTypes; - -export default AddDatabaseHelpCard; diff --git a/frontend/src/metabase/components/AddDatabaseHelpCard.styled.jsx b/frontend/src/metabase/components/AddDatabaseHelpCard.styled.jsx deleted file mode 100644 index 1a39a52d677f47b53b57d32138f3eecdcc0902f7..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/components/AddDatabaseHelpCard.styled.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import styled from "styled-components"; -import { Flex } from "grid-styled"; - -export const CardContent = styled(Flex)` - margin-top: ${props => (props.shouldDisplayHelpLink ? "8px" : 0)}; -`; - -export const HelpCardContainer = styled(Flex)` - background-color: #f9fbfb; - border-radius: 10px; - min-width: 300px; -`; - -export const IconContainer = styled(Flex)` - width: ${props => (props.hasCircle ? "52px" : "32px")}; - height: ${props => (props.hasCircle ? "52px" : "32px")}; - background-color: ${props => (props.hasCircle ? "#EEF2F5" : "transparent")}; -`; diff --git a/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.stories.tsx b/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.stories.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d10a2809136063365f52a2bd3733dab01a1123e5 --- /dev/null +++ b/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.stories.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { ComponentStory } from "@storybook/react"; +import DatabaseHelpCard from "./DatabaseHelpCard"; + +export default { + title: "Components/DatabaseHelpCard", + component: DatabaseHelpCard, +}; + +const Template: ComponentStory<typeof DatabaseHelpCard> = args => { + return <DatabaseHelpCard {...args} />; +}; + +export const Default = Template.bind({}); +Default.args = { + isHosted: false, +}; + +export const Cloud = Template.bind({}); +Cloud.args = { + isHosted: true, +}; diff --git a/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.styled.tsx b/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.styled.tsx new file mode 100644 index 0000000000000000000000000000000000000000..30a315c58460a71a1003020ecca32ccd137cd6e9 --- /dev/null +++ b/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.styled.tsx @@ -0,0 +1,69 @@ +import styled, { css } from "styled-components"; +import { color } from "metabase/lib/colors"; +import Icon from "metabase/components/Icon"; +import ExternalLink from "metabase/components/ExternalLink"; + +const CardRootMixin = css` + display: block; + padding: 1.5rem; + border: 1px solid ${color("border")}; + border-radius: 0.375rem; + background-color: ${color("white")}; + box-shadow: 0 1px 6px ${color("shadow")}; + box-sizing: border-box; +`; + +const CardHeaderMixin = css` + display: flex; + align-items: center; + margin-bottom: 1rem; +`; + +export const CardRootStatic = styled.div` + ${CardRootMixin}; +`; + +export const CardRootLink = styled(ExternalLink)` + ${CardRootMixin}; + + &:hover { + background-color: ${color("bg-light")}; + } +`; + +export const CardHeaderStatic = styled.div` + ${CardHeaderMixin}; +`; + +export const CardHeaderLink = styled(ExternalLink)` + ${CardHeaderMixin}; +`; + +export const CardTitle = styled.span` + display: block; + flex: 1 1 auto; + color: ${color("brand")}; + font-weight: bold; + margin: 0 0.5rem; +`; + +export const CardIcon = styled(Icon)` + flex: 0 0 auto; + color: ${color("brand")}; +`; + +export const CardMessage = styled.span` + display: block; + color: ${color("text-medium")}; + line-height: 1.25rem; + + &:not(:last-child) { + margin-bottom: 1.25rem; + } +`; + +export const CardLink = styled(ExternalLink)` + color: ${color("brand")}; + cursor: pointer; + font-weight: bold; +`; diff --git a/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.tsx b/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fd7b6e26045d0c3a9d80d08d2d02399774b41590 --- /dev/null +++ b/frontend/src/metabase/components/DatabaseHelpCard/DatabaseHelpCard.tsx @@ -0,0 +1,72 @@ +import React from "react"; +import { jt, t } from "ttag"; +import Settings from "metabase/lib/settings"; +import { + CardHeaderLink, + CardHeaderStatic, + CardIcon, + CardLink, + CardMessage, + CardRootLink, + CardRootStatic, + CardTitle, +} from "./DatabaseHelpCard.styled"; + +export interface DatabaseHelpCardProps { + className?: string; + engine?: string; + isHosted?: boolean; +} + +const DatabaseHelpCard = ({ + className, + engine, + isHosted, +}: DatabaseHelpCardProps): JSX.Element => { + const docsUrl = getDocsUrl(engine); + const CardRoot = isHosted ? CardRootStatic : CardRootLink; + const CardHeader = isHosted ? CardHeaderLink : CardHeaderStatic; + + return ( + <CardRoot className={className} href={isHosted ? undefined : docsUrl}> + <CardHeader href={isHosted ? docsUrl : undefined}> + <CardIcon name="info" /> + <CardTitle>{t`Need help connecting?`}</CardTitle> + <CardIcon name="external" /> + </CardHeader> + <CardMessage> + {t`Check out documentation for step-by-step directions on how to connect to your database.`} + </CardMessage> + {isHosted && ( + <CardMessage> + {jt`Docs weren't enough? ${( + <CardLink key="link" href="https://www.metabase.com/help/cloud"> + {t`Write us.`} + </CardLink> + )}`} + </CardMessage> + )} + </CardRoot> + ); +}; + +const getDocsUrl = (engine?: string): string => { + switch (engine) { + case "bigquery": + return Settings.docsUrl("administration-guide/databases/bigquery"); + case "mongo": + return Settings.docsUrl("administration-guide/databases/mongodb"); + case "mysql": + return Settings.docsUrl("administration-guide/databases/mysql"); + case "oracle": + return Settings.docsUrl("administration-guide/databases/oracle"); + case "snowflake": + return Settings.docsUrl("administration-guide/databases/snowflake"); + case "vertica": + return Settings.docsUrl("administration-guide/databases/vertica"); + default: + return Settings.docsUrl("administration-guide/01-managing-databases"); + } +}; + +export default DatabaseHelpCard; diff --git a/frontend/src/metabase/components/DatabaseHelpCard/index.ts b/frontend/src/metabase/components/DatabaseHelpCard/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5511de5fdd0f5d927f354f7e7ad5c2b442aae9c5 --- /dev/null +++ b/frontend/src/metabase/components/DatabaseHelpCard/index.ts @@ -0,0 +1 @@ +export { default } from "./DatabaseHelpCard"; diff --git a/frontend/src/metabase/containers/DatabaseHelpCard/DatabaseHelpCard.tsx b/frontend/src/metabase/containers/DatabaseHelpCard/DatabaseHelpCard.tsx new file mode 100644 index 0000000000000000000000000000000000000000..76f67b2f671f511e7e87ada4cfedf22cebb0ba97 --- /dev/null +++ b/frontend/src/metabase/containers/DatabaseHelpCard/DatabaseHelpCard.tsx @@ -0,0 +1,23 @@ +import { connect } from "react-redux"; +import DatabaseHelpCard from "metabase/components/DatabaseHelpCard"; +import { State } from "metabase-types/store"; + +export interface DatabaseHelpCardProps { + className?: string; + engine?: string; +} + +interface DatabaseHelpCardStateProps { + isHosted: boolean; +} + +const mapStateToProps = (state: State): DatabaseHelpCardStateProps => ({ + isHosted: state.settings.values["is-hosted?"], +}); + +export default connect< + DatabaseHelpCardStateProps, + unknown, + DatabaseHelpCardProps, + State +>(mapStateToProps)(DatabaseHelpCard); diff --git a/frontend/src/metabase/containers/DatabaseHelpCard/index.ts b/frontend/src/metabase/containers/DatabaseHelpCard/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5511de5fdd0f5d927f354f7e7ad5c2b442aae9c5 --- /dev/null +++ b/frontend/src/metabase/containers/DatabaseHelpCard/index.ts @@ -0,0 +1 @@ +export { default } from "./DatabaseHelpCard"; diff --git a/frontend/src/metabase/icon_paths.ts b/frontend/src/metabase/icon_paths.ts index 8a94f1a9e662e3bacadca95953a9ca1123565f82..b54fe13683e4956984d247136da2a1d3eabab5f3 100644 --- a/frontend/src/metabase/icon_paths.ts +++ b/frontend/src/metabase/icon_paths.ts @@ -185,7 +185,7 @@ export const ICON_PATHS: Record<string, any> = { "M27.448 13.42a2.051 2.051 0 0 0 4.101 0V2.052A2.05 2.05 0 0 0 29.5 0h-11.37a2.05 2.05 0 0 0 0 4.102h6.418L18.46 10.19a2.051 2.051 0 0 0 2.901 2.9l6.088-6.088v6.419zM4.102 18.58a2.051 2.051 0 0 0-4.102 0v11.369A2.05 2.05 0 0 0 2.051 32h11.37a2.051 2.051 0 1 0 0-4.102H7.002l6.088-6.087a2.05 2.05 0 1 0-2.9-2.901l-6.088 6.088v-6.419z", expand_arrow: "M16.429 28.429L.429 5.57h32z", external: - "M13.7780693,4.44451732 L5.1588494,4.44451732 C2.32615959,4.44451732 0,6.75504816 0,9.60367661 L0,25.1192379 C0,27.9699171 2.30950226,30.2783972 5.1588494,30.2783972 L18.9527718,30.2783972 C21.7854617,30.2783972 24.1116212,27.9678664 24.1116212,25.1192379 L24.1116212,19.9448453 L20.6671039,19.9448453 L20.6671039,25.1192379 C20.6671039,26.0662085 19.882332,26.8338799 18.9527718,26.8338799 L5.1588494,26.8338799 C4.21204994,26.8338799 3.44451732,26.0677556 3.44451732,25.1192379 L3.44451732,9.60367661 C3.44451732,8.656706 4.22928927,7.88903464 5.1588494,7.88903464 L13.7780693,7.88903464 L13.7780693,4.44451732 L13.7780693,4.44451732 Z M30.9990919,14.455325 L30.9990919,1 L17.5437669,1 L22.4834088,5.93964193 L17.2225866,11.2004641 L20.8001918,14.7780693 L26.061014,9.51724709 L30.9990919,14.455325 L30.9990919,14.455325 L30.9990919,14.455325 Z", + "M 25.144 32 H 6.858 A 6.856 6.856 90 0 1 0 25.142 V 6.86 A 6.858 6.858 90 0 1 6.86 0 h 6.856 v 4.572 H 6.86 a 2.286 2.286 90 0 0 -2.286 2.286 v 18.284 a 2.286 2.286 90 0 0 2.286 2.286 h 18.286 a 2.286 2.286 90 0 0 2.284 -2.286 V 18.286 H 32 v 6.856 A 6.858 6.858 90 0 1 25.144 32 Z m -10.286 -11.622 L 11.624 17.14 l 12.57 -12.57 H 18.286 V 0 h 11.428 A 2.286 2.286 90 0 1 32 2.286 v 11.428 h -4.572 V 7.806 L 14.86 20.378 Z", eye: "M30.622 18.49c-.549.769-1.46 1.86-2.737 3.273-1.276 1.414-2.564 2.614-3.866 3.602-2.297 1.757-4.963 2.635-8 2.635-3.062 0-5.741-.878-8.038-2.635-1.302-.988-2.59-2.188-3.866-3.602-1.276-1.413-2.188-2.504-2.737-3.272-.549-.769-.9-1.277-1.053-1.524-.433-.63-.433-1.276 0-1.934.128-.247.472-.755 1.034-1.524.561-.768 1.48-1.852 2.756-3.252 1.276-1.4 2.564-2.593 3.866-3.581C10.303 4.892 12.982 4 16.019 4c3.011 0 5.678.892 8 2.676 1.302.988 2.59 2.182 3.866 3.581 1.276 1.4 2.195 2.484 2.756 3.252.562.769.906 1.277 1.034 1.524.433.63.433 1.276 0 1.934-.153.247-.504.755-1.053 1.524zm-1.516-3.214c-.248.376-.248 1.089.034 1.499l-.11-.16-.088-.17a21.93 21.93 0 0 0-.784-1.121c-.483-.66-1.338-1.67-2.546-2.995-1.154-1.266-2.306-2.333-3.466-3.214-1.781-1.368-3.788-2.04-6.127-2.04-2.365 0-4.385.673-6.179 2.05-1.146.87-2.298 1.938-3.452 3.204-1.208 1.325-2.063 2.334-2.546 2.995a21.93 21.93 0 0 0-.784 1.12l-.075.145-.09.135c.249-.376.249-1.089-.033-1.499l.08.122c.105.17.432.644.941 1.356.466.653 1.313 1.666 2.517 3 1.152 1.275 2.3 2.346 3.451 3.22 1.752 1.339 3.773 2.001 6.17 2.001 2.37 0 4.379-.661 6.14-2.008 1.143-.867 2.291-1.938 3.443-3.214 1.204-1.333 2.05-2.346 2.517-2.999.509-.712.836-1.186.942-1.356l.045-.071zm-17.353 5.663C10.584 19.709 10 18.237 10 16.522c0-1.744.584-3.224 1.753-4.439 1.168-1.215 2.59-1.822 4.268-1.822 1.65 0 3.058.607 4.226 1.822C21.416 13.298 22 14.778 22 16.522c0 1.715-.584 3.187-1.753 4.417-1.168 1.229-2.577 1.844-4.226 1.844-1.677 0-3.1-.615-4.268-1.844zm6.265-2.12c.624-.655.906-1.368.906-2.297 0-.957-.281-1.67-.893-2.307-.592-.616-1.203-.879-2.01-.879-.84 0-1.462.266-2.052.88-.612.636-.893 1.35-.893 2.306 0 .929.282 1.642.906 2.298.59.62 1.207.887 2.039.887.8 0 1.405-.264 1.997-.887z", eye_crossed_out: @@ -244,7 +244,7 @@ export const ICON_PATHS: Record<string, any> = { }, }, info: - "M16 0 A16 16 0 0 1 16 32 A16 16 0 0 1 16 0 M19 15 L13 15 L13 26 L19 26 z M16 6 A3 3 0 0 0 16 12 A3 3 0 0 0 16 6", + "M 17.7 12 v 14 H 13.512 V 12 h 4.184 Z m 0.43 -3.834 c 0 0.334 -0.066 0.646 -0.2 0.94 c -0.136 0.292 -0.32 0.548 -0.556 0.768 c -0.234 0.22 -0.506 0.396 -0.816 0.526 a 2.534 2.534 90 0 1 -1.95 0 a 2.694 2.694 90 0 1 -0.79 -0.526 a 2.43 2.43 90 0 1 -0.54 -0.77 a 2.276 2.276 90 0 1 -0.196 -0.938 c 0 -0.34 0.066 -0.66 0.196 -0.958 a 2.488 2.488 90 0 1 1.33 -1.31 a 2.614 2.614 90 0 1 2.768 0.526 c 0.232 0.226 0.418 0.488 0.552 0.784 c 0.136 0.296 0.202 0.616 0.202 0.96 Z M 16.002 32 a 16 16 90 1 0 0 -32 a 16 16 90 0 0 0 32 Z", info_outline: "M16 29c7.18 0 13-5.82 13-13S23.18 3 16 3 3 8.82 3 16s5.82 13 13 13zm0 3C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm1.697-20h-4.185v14h4.185V12zm.432-3.834c0-.342-.067-.661-.203-.958a2.527 2.527 0 0 0-1.37-1.31 2.613 2.613 0 0 0-.992-.188c-.342 0-.661.062-.959.189a2.529 2.529 0 0 0-1.33 1.309c-.13.297-.195.616-.195.958 0 .334.065.646.196.939.13.292.31.549.54.77.23.22.492.395.79.526.297.13.616.196.958.196.351 0 .682-.066.992-.196.31-.13.583-.306.817-.527a2.47 2.47 0 0 0 .553-.77c.136-.292.203-.604.203-.938z", insight: diff --git a/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.styled.tsx b/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.styled.tsx index 1e2b95eba6b30de7b76ca483eba9a9ddc4ad735f..b8dbda18a80594878dbba61c973fe11aed75fa57 100644 --- a/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.styled.tsx +++ b/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.styled.tsx @@ -1,20 +1,22 @@ import styled from "styled-components"; -import { color } from "metabase/lib/colors"; -import AddDatabaseHelpCard from "metabase/components/AddDatabaseHelpCard"; +import { breakpointMinLarge } from "metabase/styled-components/theme"; interface DatabaseHelpRootProps { isVisible: boolean; } export const DatabaseHelpRoot = styled.div<DatabaseHelpRootProps>` - position: fixed; - left: 1em; - bottom: 1em; - transform: ${props => `translateY(${props.isVisible ? "0" : "200%"})`}; - transition: transform 0.4s; -`; + display: ${props => (props.isVisible ? "block" : "none")}; + margin-bottom: 1.75rem; -export const DatabaseHelpCard = styled(AddDatabaseHelpCard)` - border: 1px solid ${color("border")}; - background-color: ${color("white")}; + ${breakpointMinLarge} { + display: block; + position: fixed; + right: 2em; + bottom: 2em; + max-width: 20%; + margin-bottom: 0; + transform: ${props => `translateY(${props.isVisible ? "0" : "200%"})`}; + transition: transform 0.4s; + } `; diff --git a/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.tsx b/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.tsx index fade04d8bcf1c3223d8d85307f6bcc7dfdcf96f9..70b48911b70f75a6b55510ff27669ee41ca59820 100644 --- a/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.tsx +++ b/frontend/src/metabase/setup/components/DatabaseHelp/DatabaseHelp.tsx @@ -1,5 +1,6 @@ import React from "react"; -import { DatabaseHelpRoot, DatabaseHelpCard } from "./DatabaseHelp.styled"; +import DatabaseHelpCard from "metabase/containers/DatabaseHelpCard"; +import { DatabaseHelpRoot } from "./DatabaseHelp.styled"; export interface DatabaseHelpProps { engine?: string; @@ -13,11 +14,8 @@ const DatabaseHelp = ({ const isVisible = isStepActive && engine != null; return ( - <DatabaseHelpRoot - isVisible={isVisible} - data-testid="database-setup-help-card" - > - <DatabaseHelpCard {...{ engine, hasCircle: false }} /> + <DatabaseHelpRoot isVisible={isVisible}> + <DatabaseHelpCard engine={engine} /> </DatabaseHelpRoot> ); }; diff --git a/frontend/test/metabase/components/AddDatabaseHelpCard.unit.spec.js b/frontend/test/metabase/components/AddDatabaseHelpCard.unit.spec.js deleted file mode 100644 index aafdc31c039a331c7d33a8bc93fc41dd6d1813a6..0000000000000000000000000000000000000000 --- a/frontend/test/metabase/components/AddDatabaseHelpCard.unit.spec.js +++ /dev/null @@ -1,114 +0,0 @@ -import React from "react"; -import { render, screen } from "@testing-library/react"; - -import MetabaseSettings from "metabase/lib/settings"; - -import AddDatabaseHelpCard, { - CLOUD_HELP_URL, - ENGINE_DOCS, - GENERAL_DB_DOC, -} from "metabase/components/AddDatabaseHelpCard"; - -const ENGINES = { - redshift: { - "driver-name": "Amazon Redshift", - }, - bigquery: { - "driver-name": "BigQuery (Deprecated Driver)", - "superseded-by": "bigquery-cloud-sdk", - }, - "bigquery-cloud-sdk": { - "driver-name": "BigQuery", - }, - druid: { - "driver-name": "Druid", - }, - googleanalytics: { - "driver-name": "Google Analytics", - }, - h2: { - "driver-name": "H2", - }, - mongo: { - "driver-name": "MongoDB", - }, - mysql: { - "driver-name": "MySQL", - }, - postgres: { - "driver-name": "PostgreSQL", - }, - presto: { - "driver-name": "Presto", - }, - snowflake: { - "driver-name": "Snowflake", - }, - sparksql: { - "driver-name": "Spark SQL", - }, - sqlserver: { - "driver-name": "SQL Server", - }, - sqlite: { - "driver-name": "SQLite", - }, -}; - -function setup({ engine = "mongo", isHosted = false } = {}) { - jest - .spyOn(MetabaseSettings, "get") - .mockImplementation(setting => (setting === "engines" ? ENGINES : {})); - jest.spyOn(MetabaseSettings, "isHosted").mockReturnValue(isHosted); - return render(<AddDatabaseHelpCard engine={engine} />); -} - -describe("AddDatabaseHelpCard", () => { - Object.entries(ENGINES).forEach(([engine, info]) => { - const expectedCard = ENGINES[engine]["superseded-by"] == null; - const expectedName = ENGINE_DOCS[engine] - ? info["driver-name"] - : "your database"; - const expectedDocsLink = ENGINE_DOCS[engine] || GENERAL_DB_DOC; - - if (expectedCard) { - it(`correctly displays hints for ${engine} setup`, () => { - setup({ engine }); - - const helpText = screen.getByText( - `Need help setting up ${expectedName}?`, - ); - const docsLink = screen.getByText("Our docs can help."); - - expect(helpText).toBeInTheDocument(); - expect(docsLink).toBeInTheDocument(); - expect(docsLink.getAttribute("href")).toBe(expectedDocsLink); - }); - } else { - it(`correctly hides hints for ${engine} setup`, () => { - setup({ engine }); - - const helpText = screen.queryByText( - `Need help setting up ${expectedName}?`, - ); - const docsLink = screen.queryByText("Our docs can help."); - - expect(helpText).not.toBeInTheDocument(); - expect(docsLink).not.toBeInTheDocument(); - }); - } - }); - - it("should display a help link if it's a cloud instance", () => { - const { queryByText } = setup({ isHosted: true }); - const helpLink = queryByText(/write us/i); - expect(helpLink).toBeInTheDocument(); - expect(helpLink.getAttribute("href")).toBe(CLOUD_HELP_URL); - }); - - it("should not display a help link if it's a self-hosted instance", () => { - const { queryByText } = setup({ isHosted: false }); - const helpLink = queryByText(/write us/i); - expect(helpLink).not.toBeInTheDocument(); - }); -}); diff --git a/frontend/test/metabase/scenarios/admin/databases/add-presto.cy.spec.js b/frontend/test/metabase/scenarios/admin/databases/add-presto.cy.spec.js index 6a9238ab2668b3c803e9acb5c78d98dd8240af53..4d84eacd34e72851c5d702a4579326a6f385b596 100644 --- a/frontend/test/metabase/scenarios/admin/databases/add-presto.cy.spec.js +++ b/frontend/test/metabase/scenarios/admin/databases/add-presto.cy.spec.js @@ -59,8 +59,7 @@ describe("admin > database > add > Presto", () => { // This should be disabled but we'll not add that assertion until we mark all the required fields in the form cy.button("Save"); - cy.findByText("Need help setting up your database?"); - cy.findByRole("link", { name: "Our docs can help." }); + cy.findByText("Need help connecting?"); cy.contains("This is our new Presto driver."); diff --git a/frontend/test/metabase/scenarios/admin/databases/add.cy.spec.js b/frontend/test/metabase/scenarios/admin/databases/add.cy.spec.js index 03d1898d2fc04968c9fb977d3215dca857292dd4..d1cc6be5e67fecd871d26c7d0df4f7652632e53d 100644 --- a/frontend/test/metabase/scenarios/admin/databases/add.cy.spec.js +++ b/frontend/test/metabase/scenarios/admin/databases/add.cy.spec.js @@ -170,22 +170,7 @@ describe("scenarios > admin > databases > add", () => { it("should display a setup help card", () => { cy.visit("/admin/databases/create"); - cy.findByTestId("database-setup-help-card").within(() => { - cy.findByText(/Need help setting up (.*)\?/i); - cy.findByRole("link", { name: /Our docs can help/i }); - }); - - cy.get("#formField-engine").click(); - cy.findByText("MySQL").click(); - cy.findByTestId("database-setup-help-card").findByText( - "Need help setting up MySQL?", - ); - - cy.get("#formField-engine").click(); - cy.findByText("SQLite").click(); - cy.findByTestId("database-setup-help-card").findByText( - "Need help setting up your database?", - ); + cy.findByText("Need help connecting?"); }); it("should respect users' decision to manually sync large database (metabase#17450)", () => { @@ -294,13 +279,11 @@ describe("scenarios > admin > databases > add", () => { chooseDatabase("BigQuery"); cy.findByText("BigQuery"); - cy.findByText("Need help setting up your database?"); - cy.findByText("The old driver has been deprecated", { exact: false }); + cy.findByText("Need help connecting?"); cy.findByText("find it here").click(); cy.findByText("BigQuery (Deprecated Driver)"); - cy.findByText("Need help setting up your database?").should("not.exist"); - cy.findByText("This driver will be removed", { exact: false }); + cy.findByText("Need help connecting?"); }); }); diff --git a/frontend/test/metabase/scenarios/admin/databases/edit.cy.spec.js b/frontend/test/metabase/scenarios/admin/databases/edit.cy.spec.js index b162170f85fbcab8e1abfcf4aa4660477c87a078..71828c5b602683b7470bb39d9ec01302e3dc5dca 100644 --- a/frontend/test/metabase/scenarios/admin/databases/edit.cy.spec.js +++ b/frontend/test/metabase/scenarios/admin/databases/edit.cy.spec.js @@ -254,7 +254,7 @@ describe("scenarios > admin > databases > edit", () => { cy.visit("/admin/databases/1"); cy.wait("@loadDatabase"); - cy.findByTestId("database-setup-help-card").should("not.exist"); + cy.findByText("Need help connecting?").should("not.exist"); }); }); }); diff --git a/frontend/test/metabase/scenarios/onboarding/home/homepage.cy.spec.js b/frontend/test/metabase/scenarios/onboarding/home/homepage.cy.spec.js index 55faa13125130ae9d180fae0ad15042b3be1266b..8da028ac26eb08560305ae2b3189266edc21fd6c 100644 --- a/frontend/test/metabase/scenarios/onboarding/home/homepage.cy.spec.js +++ b/frontend/test/metabase/scenarios/onboarding/home/homepage.cy.spec.js @@ -13,7 +13,7 @@ describe("scenarios > home > homepage", () => { it("should allow basic navigation", () => { cy.visit("/"); cy.findByText("Add my data").click(); - cy.findByText("Need help setting up your database?"); + cy.findByText("Need help connecting?"); cy.visit("/"); cy.findByText("invite another teammate").click(); @@ -34,7 +34,7 @@ describe("scenarios > home > homepage", () => { cy.visit("/"); cy.findByText("Add a database").click(); - cy.findByText("Need help setting up your database?"); + cy.findByText("Need help connecting?"); }); it("should show pinned dashboards", () => { diff --git a/frontend/test/metabase/scenarios/onboarding/setup/setup.cy.spec.js b/frontend/test/metabase/scenarios/onboarding/setup/setup.cy.spec.js index d00a1de6b320ba8a79f02d1d55a6d55bc237ba5e..76058f8aa2c3af3b063f183436b15b81e427dcf5 100644 --- a/frontend/test/metabase/scenarios/onboarding/setup/setup.cy.spec.js +++ b/frontend/test/metabase/scenarios/onboarding/setup/setup.cy.spec.js @@ -95,31 +95,26 @@ describe("scenarios > setup", () => { cy.findByText("Add your data"); // test database setup help card is NOT displayed before DB is selected - cy.findByTestId("database-setup-help-card").should("not.be.visible"); + cy.findByText("Need help connecting?").should("not.be.visible"); // test that you can return to user settings if you want cy.findByText("Hi, Testy. Nice to meet you!").click(); cy.findByLabelText("Email").should("have.value", "testy@metabase.test"); // test database setup help card is NOT displayed on other steps - cy.findByTestId("database-setup-help-card").should("not.be.visible"); + cy.findByText("Need help connecting?").should("not.be.visible"); // now back to database setting cy.findByText("Next").click(); - // check database setup card changes copy + // check database setup card is visible cy.findByText("MySQL").click(); - cy.findByTestId("database-setup-help-card").within(() => { - cy.findByText("Need help setting up MySQL?"); - cy.findByRole("link", { name: /Our docs can help/i }); - }); + cy.findByText("Need help connecting?").should("be.visible"); cy.findByLabelText("Remove database").click(); cy.findByPlaceholderText("Search for a database…").type("SQL"); cy.findByText("SQLite").click(); - cy.findByTestId("database-setup-help-card").findByText( - "Need help setting up your database?", - ); + cy.findByText("Need help connecting?"); // add h2 database cy.findByLabelText("Remove database").click(); @@ -139,7 +134,7 @@ describe("scenarios > setup", () => { .click(); // test database setup help card is hidden on the next step - cy.findByTestId("database-setup-help-card").should("not.be.visible"); + cy.findByText("Need help connecting?").should("not.be.visible"); // ================ // Data Preferences