Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CTA to migrate to MB Cloud in admin panel #14458

Merged
merged 8 commits into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { t } from "ttag";
import { Flex } from "grid-styled";

import Button from "metabase/components/Button";
import MarginHostingCTA from "metabase/admin/settings/components/widgets/MarginHostingCTA";

import SettingsBatchForm from "./SettingsBatchForm";

import MetabaseAnalytics from "metabase/lib/analytics";
import MetabaseSettings from "metabase/lib/settings";

import {
sendTestEmail,
Expand All @@ -21,6 +24,10 @@ const SEND_TEST_BUTTON_STATES = {
success: t`Sent!`,
};

const isHosted = MetabaseSettings.get("site-url")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might it be better to imitate the way some of the settings have an accessor?

  adminEmail() {
    return this.get("admin-email");
  }

but for is hosted. then when the env var is exposed this can change in one place without the isHosted definiition duplicated in many places?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, perfect — I was thinking along these lines but didn't know where to look. I'll amend.

.toLowerCase()
.includes("metabaseapp.com");

@connect(
null,
{ sendTestEmail, updateEmailSettings, clearEmailSettings },
Expand Down Expand Up @@ -68,33 +75,38 @@ export default class SettingsEmailForm extends Component {
render() {
const { sendingEmail } = this.state;
return (
<SettingsBatchForm
ref={form => (this._form = form && form.getWrappedInstance())}
{...this.props}
updateSettings={this.props.updateEmailSettings}
disable={sendingEmail !== "default"}
renderExtraButtons={({ disabled, valid, dirty, submitting }) => {
return [
valid && !dirty && submitting === "default" ? (
<Flex justifyContent="space-between">
<SettingsBatchForm
ref={form => (this._form = form && form.getWrappedInstance())}
{...this.props}
updateSettings={this.props.updateEmailSettings}
disable={sendingEmail !== "default"}
renderExtraButtons={({ disabled, valid, dirty, submitting }) => {
return [
valid && !dirty && submitting === "default" ? (
<Button
mr={1}
success={sendingEmail === "success"}
disabled={disabled}
onClick={this.sendTestEmail}
>
{SEND_TEST_BUTTON_STATES[sendingEmail]}
</Button>
) : null,
<Button
mr={1}
success={sendingEmail === "success"}
disabled={disabled}
onClick={this.sendTestEmail}
onClick={() => this.clearEmailSettings()}
>
{SEND_TEST_BUTTON_STATES[sendingEmail]}
</Button>
) : null,
<Button
mr={1}
disabled={disabled}
onClick={() => this.clearEmailSettings()}
>
{t`Clear`}
</Button>,
];
}}
/>
{t`Clear`}
</Button>,
];
}}
/>
{!isHosted && (
<MarginHostingCTA tagline={t`Have your email configured for you.`} />
)}
</Flex>
);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import React, { Component } from "react";
import { Link } from "react-router";
import Icon from "metabase/components/Icon";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
import { Flex } from "grid-styled";
import { SetupApi } from "metabase/services";
import { t } from "ttag";
import { color } from "metabase/lib/colors";
import MetabaseSettings from "metabase/lib/settings";

import Icon from "metabase/components/Icon";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
import MarginHostingCTA from "metabase/admin/settings/components/widgets/MarginHostingCTA";

const isHosted = MetabaseSettings.get("site-url")
.toLowerCase()
.includes("metabaseapp.com");

const TaskList = ({ tasks }) => (
<ol>
Expand Down Expand Up @@ -101,28 +109,34 @@ export default class SettingsSetupList extends Component {
}

return (
<div className="px2">
<h2>{t`Getting set up`}</h2>
<p className="mt1">{t`A few things you can do to get the most out of Metabase.`}</p>
<LoadingAndErrorWrapper
loading={!this.state.tasks}
error={this.state.error}
>
{() => (
<div style={{ maxWidth: 468 }}>
{nextTask && (
<TaskSection
name={t`Recommended next step`}
tasks={[nextTask]}
/>
)}
{tasks.map((section, index) => (
<TaskSection {...section} key={index} />
))}
</div>
)}
</LoadingAndErrorWrapper>
</div>
<Flex justifyContent="space-between">
<div className="px2">
<h2>{t`Getting set up`}</h2>
<p className="mt1">{t`A few things you can do to get the most out of Metabase.`}</p>
<LoadingAndErrorWrapper
loading={!this.state.tasks}
error={this.state.error}
>
{() => (
<div style={{ maxWidth: 468 }}>
{nextTask && (
<TaskSection
name={t`Recommended next step`}
tasks={[nextTask]}
/>
)}
{tasks.map((section, index) => (
<TaskSection {...section} key={index} />
))}
</div>
)}
</LoadingAndErrorWrapper>
</div>

{!isHosted && (
<MarginHostingCTA tagline={t`Have your server maintained for you.`} />
)}
</Flex>
);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { t, jt } from "ttag";
import { Flex, Box } from "grid-styled";
import MetabaseSettings from "metabase/lib/settings";
import SettingsSetting from "./SettingsSetting";

import HostingInfoLink from "metabase/admin/settings/components/widgets/HostingInfoLink";
import Icon from "metabase/components/Icon";
import Text from "metabase/components/type/Text";

const isHosted = MetabaseSettings.get("site-url")
.toLowerCase()
.includes("metabaseapp.com");

export default class SettingsUpdatesForm extends Component {
static propTypes = {
elements: PropTypes.array,
Expand All @@ -13,10 +22,13 @@ export default class SettingsUpdatesForm extends Component {
if (MetabaseSettings.versionIsLatest()) {
const currentVersion = MetabaseSettings.currentVersion();
return (
<div className="p2 bg-brand bordered rounded border-brand text-white text-bold">
{jt`You're running Metabase ${formatVersion(
currentVersion,
)} which is the latest and greatest!`}
<div>
<div className="p2 bg-brand bordered rounded border-brand text-white text-bold">
{jt`You're running Metabase ${formatVersion(
currentVersion,
)} which is the latest and greatest!`}
</div>
{!isHosted && <HostingCTA />}
</div>
);
} else if (MetabaseSettings.newVersionAvailable()) {
Expand All @@ -42,14 +54,19 @@ export default class SettingsUpdatesForm extends Component {
</a>
</div>

<div className="text-medium">
<h3 className="py3 text-uppercase">{t`What's Changed:`}</h3>
<div
className="text-medium bordered rounded p2 mt2 overflow-y-scroll"
style={{ height: 330 }}
>
<h3 className="pb3 text-uppercase">{t`What's Changed:`}</h3>

<Version version={versionInfo.latest} />

{versionInfo.older &&
versionInfo.older.map(version => <Version version={version} />)}
</div>

{!isHosted && <HostingCTA />}
</div>
);
} else {
Expand Down Expand Up @@ -107,6 +124,33 @@ function Version({ version }) {
);
}

function HostingCTA() {
return (
<Flex
justifyContent="space-between"
alignItems="center"
className="rounded bg-light mt4 text-brand py2 px1"
>
<Flex>
<Flex
className="circular bg-medium align-center justify-center ml1 mr2"
h={32}
w={52}
>
<Icon name="cloud" size={24} />
</Flex>
<div>
<Text className="text-brand mb0">{t`Want to have upgrades taken care of for you?`}</Text>
<Text className="text-brand text-bold">{t`Migrate to Metabase Cloud.`}</Text>
</div>
</Flex>
<Box className="pr1">
<HostingInfoLink text={t`Learn more`} />
</Box>
</Flex>
);
}

function formatVersion(versionLabel = "") {
return versionLabel.replace(/^v/, "");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import ExternalLink from "metabase/components/ExternalLink";

const HostingInfoLink = ({ text }) => (
<ExternalLink
className="bordered rounded border-brand bg-brand-hover text-white-hover px2 py1 text-bold text-center"
href={"https://www.metabase.com/migrate/from/selfhosted"}
target="_blank"
>
{text}
</ExternalLink>
);

export default HostingInfoLink;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import { t } from "ttag";

import Icon from "metabase/components/Icon";
import Text from "metabase/components/type/Text";
import HostingInfoLink from "metabase/admin/settings/components/widgets/HostingInfoLink";

const MarginHostingCTA = ({ tagline }) => (
<div
className="border-left border-brand text-brand px4"
style={{ height: 172 }}
>
<Icon name="cloud" size={48} style={{ color: "#B9D8F4" }} />
<div className="pb3">
<Text className="text-brand mb0">{tagline}</Text>
<Text className="text-brand text-bold">{t`Migrate to Metabase Cloud.`}</Text>
</div>

<HostingInfoLink text={t`Learn more`} />
</div>
);

export default MarginHostingCTA;
2 changes: 2 additions & 0 deletions frontend/src/metabase/icon_paths.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.