Skip to content

Commit

Permalink
Embed homepage, MS4 (metabase#41990)
Browse files Browse the repository at this point in the history
* use css modules instead of inline styles for cursor: default (metabase#41644)

* add toast notification after the feedback (metabase#41575)

* fix modal submit sending data while button says skip (metabase#41784)

* fix: it should not send the feedback if button says skip

* add comment explaining why we check that getLastFeedbackCall() is undefined

* embedding homepage analytics (metabase#41725)

* rename defaultTab -> initialTab

* add events schema for embedding-homepage

* fix stories

* add analytics, e2e tests and fix typo in dismiss reason

* copy embed_flow schema for better diff in the next commit

* adds isExampleDashboard to trackStaticEmbedPublished

* utm tags

* fix bug of is_example_dashboard

* better test names

* refactor embed homepage status type

* "() => {}" => "_.noop"

* add "Setup embedding" to the admin setup checklist (metabase#41638)

* add setup embedding to the admin setup checklist

* restore whitespace as it was before

* i miss prettier (whitespace again)

* Clean up check list for embedding

Largely making a new entry for the embedding info just to fight long
lines. `:embedding-homepage-dismissed-as-done` just made the maps really
long. If we have a `:done?` under an `:embedding` keyword it reads much
more naturally.

Also, The previous diff was calling `boolean` on a var rather than
invoking the var:

```clojure
:embedding-app-origin (boolean embed.settings/embedding-app-origin)
;;                             ^^^^^^^^^^^^^^ needs to be (invoked)
```

---------

Co-authored-by: dan sutton <dan@dpsutton.com>

* Change utm tags for embedding homepage links (metabase#42042)

* update utm tags

* utm_media -> utm_content

* add description to the checklist setup step (metabase#42200)

---------

Co-authored-by: dan sutton <dan@dpsutton.com>
  • Loading branch information
npretto and dpsutton authored May 3, 2024
1 parent b890780 commit 5550010
Show file tree
Hide file tree
Showing 18 changed files with 545 additions and 71 deletions.
78 changes: 78 additions & 0 deletions e2e/test/scenarios/onboarding/embedding-homepage.cy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
describeWithSnowplow,
expectGoodSnowplowEvent,
expectNoBadSnowplowEvents,
isEE,
main,
popover,
resetSnowplow,
restore,
} from "e2e/support/helpers";

describeWithSnowplow("scenarios > embedding-homepage > snowplow events", () => {
beforeEach(() => {
restore("default");
resetSnowplow();

cy.signInAsAdmin();
cy.intercept("GET", "/api/session/properties", req => {
req.continue(res => {
res.body["embedding-homepage"] = "visible";
res.body["setup-embedding-autoenabled"] = true;
res.body["example-dashboard-id"] = 1;
res.body["setup-license-active-at-setup"] = true;
res.send();
});
});
});

afterEach(() => {
expectNoBadSnowplowEvents();
});

it("clicking on the quickstart button should send the 'embedding_homepage_quickstart_click' event", () => {
cy.visit("/");
main().findByText("Interactive").click();

main()
.findByText("Build it with the quick start")
// we don't want to actually visit the page and spam the analytics of the website
.closest("a")
.invoke("removeAttr", "href")
.click();

expectGoodSnowplowEvent({
event: "embedding_homepage_quickstart_click",
initial_tab: isEE ? "interactive" : "static",
});

// check that we didn't actually navigate to the page
cy.url().should("eq", Cypress.config().baseUrl + "/");
});

it("opening the example dashboard from the button should send the 'embedding_homepage_example_dashboard_click' event", () => {
cy.visit("/");

main().findByText("Static").click();

// the example-dashboard-id is mocked, it's normal that we'll get to a permision error page
main().findByText("Embed this example dashboard").click();

expectGoodSnowplowEvent({
event: "embedding_homepage_example_dashboard_click",
initial_tab: isEE ? "interactive" : "static",
});
});

it("dismissing the homepage should send the 'embedding_homepage_dismissed' event", () => {
cy.visit("/");

main().findByText("Hide these").click();
popover().findByText("Embedding done, all good").click();

expectGoodSnowplowEvent({
event: "embedding_homepage_dismissed",
dismiss_reason: "dismissed-done",
});
});
});
16 changes: 10 additions & 6 deletions frontend/src/metabase-types/api/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,15 @@ interface InstanceSettings {
"user-visibility": string | null;
}

export type EmbeddingHomepageDismissReason =
| "dismissed-done"
| "dismissed-run-into-issues"
| "dismissed-not-interested-now";
export type EmbeddingHomepageStatus =
| EmbeddingHomepageDismissReason
| "visible"
| "hidden";

interface AdminSettings {
"active-users-count"?: number;
"deprecation-notice-version"?: string;
Expand All @@ -234,12 +243,7 @@ interface AdminSettings {
"version-info": VersionInfo | null;
"last-acknowledged-version": string | null;
"show-static-embed-terms": boolean | null;
"embedding-homepage":
| "visible"
| "hidden"
| "dismissed-done"
| "dismissed-run-into-issues"
| "dismissed-not-interested-now";
"embedding-homepage": EmbeddingHomepageStatus;
"setup-embedding-autoenabled": boolean;
"setup-license-active-at-setup": boolean;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ export const Default: Story = {
<EmbedHomepageView
{...args}
exampleDashboardId={args.hasExampleDashboard ? 1 : null}
key={args.defaultTab}
key={args.initialTab}
/>
);
},
args: {
embeddingAutoEnabled: true,
hasExampleDashboard: true,
licenseActiveAtSetup: true,
defaultTab: "interactive",
initialTab: "interactive",
interactiveEmbeddingQuickstartUrl:
"https://www.metabase.com/docs/latest/embedding/interactive-embedding-quick-start-guide.html",
embeddingDocsUrl:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { useMemo, useState } from "react";
import { t } from "ttag";

import { updateSetting } from "metabase/admin/settings/settings";
import { useSendProductFeedbackMutation } from "metabase/api/product-feedback";
import { useSetting } from "metabase/common/hooks";
import { getPlan } from "metabase/common/utils/plan";
import { useDispatch, useSelector } from "metabase/lib/redux";
import { isEEBuild } from "metabase/lib/utils";
import { addUndo } from "metabase/redux/undo";
import { getDocsUrl, getSetting } from "metabase/selectors/settings";
import type { EmbeddingHomepageDismissReason } from "metabase-types/api";

import { EmbedHomepageView } from "./EmbedHomepageView";
import { FeedbackModal } from "./FeedbackModal";
import type { EmbedHomepageDismissReason } from "./types";
import { dismissEmbeddingHomepage } from "./actions";

export const EmbedHomepage = () => {
const [feedbackModalOpened, setFeedbackModalOpened] = useState(false);
Expand Down Expand Up @@ -45,7 +47,9 @@ export const EmbedHomepage = () => {
getPlan(getSetting(state, "token-features")),
);

const defaultTab = useMemo(() => {
const utmTags = `?utm_source=product&source_plan=${plan}&utm_content=embedding-homepage`;

const initialTab = useMemo(() => {
// we want to show the interactive tab for EE builds
// unless it's a starter cloud plan, which is EE build but doesn't have interactive embedding
if (isEEBuild()) {
Expand All @@ -54,11 +58,11 @@ export const EmbedHomepage = () => {
return "static";
}, [plan]);

const onDismiss = (reason: EmbedHomepageDismissReason) => {
const onDismiss = (reason: EmbeddingHomepageDismissReason) => {
if (reason === "dismissed-run-into-issues") {
setFeedbackModalOpened(true);
} else {
dispatch(updateSetting({ key: "embedding-homepage", value: reason }));
dispatch(dismissEmbeddingHomepage(reason));
}
};

Expand All @@ -69,19 +73,19 @@ export const EmbedHomepage = () => {
comment?: string;
email?: string;
}) => {
dispatch(
updateSetting({
key: "embedding-homepage",
value: "dismiss-run-into-issues",
}),
);
dispatch(dismissEmbeddingHomepage("dismissed-run-into-issues"));

setFeedbackModalOpened(false);
sendProductFeedback({
comment,
email: email,
source: "embedding-homepage-dismiss",
});
if (comment || email) {
sendProductFeedback({
comment,
email: email,
source: "embedding-homepage-dismiss",
});
dispatch(
addUndo({ message: t`Your feedback was submitted, thank you.` }),
);
}
};

return (
Expand All @@ -91,13 +95,17 @@ export const EmbedHomepage = () => {
exampleDashboardId={exampleDashboardId}
embeddingAutoEnabled={embeddingAutoEnabled}
licenseActiveAtSetup={licenseActiveAtSetup}
defaultTab={defaultTab}
interactiveEmbeddingQuickstartUrl={interactiveEmbeddingQuickStartUrl}
embeddingDocsUrl={embeddingDocsUrl}
// eslint-disable-next-line no-unconditional-metabase-links-render -- only visible to admins
analyticsDocsUrl="https://www.metabase.com/learn/customer-facing-analytics/"
learnMoreInteractiveEmbedUrl={learnMoreInteractiveEmbedding}
learnMoreStaticEmbedUrl={learnMoreStaticEmbedding}
initialTab={initialTab}
interactiveEmbeddingQuickstartUrl={
interactiveEmbeddingQuickStartUrl + utmTags
}
embeddingDocsUrl={embeddingDocsUrl + utmTags}
analyticsDocsUrl={
// eslint-disable-next-line no-unconditional-metabase-links-render -- only visible to admins
"https://www.metabase.com/learn/customer-facing-analytics/" + utmTags
}
learnMoreInteractiveEmbedUrl={learnMoreInteractiveEmbedding + utmTags}
learnMoreStaticEmbedUrl={learnMoreStaticEmbedding + utmTags}
/>
<FeedbackModal
opened={feedbackModalOpened}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Link } from "react-router";
import { jt, t } from "ttag";

import ExternalLink from "metabase/core/components/ExternalLink";
import CS from "metabase/css/core/index.css";
import {
Anchor,
Card,
Expand All @@ -12,17 +13,18 @@ import {
Text,
Title,
} from "metabase/ui";
import type { EmbeddingHomepageDismissReason } from "metabase-types/api";

import { InteractiveTabContent } from "./InteractiveTabContent";
import { StaticTabContent } from "./StaticTabContent";
import type { EmbedHomepageDismissReason } from "./types";
import type { EmbeddingHomepageInitialTab } from "./types";

export type EmbedHomepageViewProps = {
embeddingAutoEnabled: boolean;
exampleDashboardId: number | null;
licenseActiveAtSetup: boolean;
defaultTab: "interactive" | "static";
onDismiss: (reason: EmbedHomepageDismissReason) => void;
initialTab: EmbeddingHomepageInitialTab;
onDismiss: (reason: EmbeddingHomepageDismissReason) => void;
// links
interactiveEmbeddingQuickstartUrl: string;
embeddingDocsUrl: string;
Expand All @@ -34,7 +36,7 @@ export type EmbedHomepageViewProps = {
export const EmbedHomepageView = (props: EmbedHomepageViewProps) => {
const {
embeddingAutoEnabled,
defaultTab,
initialTab,
embeddingDocsUrl,
analyticsDocsUrl,
onDismiss,
Expand All @@ -49,7 +51,7 @@ export const EmbedHomepageView = (props: EmbedHomepageViewProps) => {
<Text
fw="bold"
color="brand"
style={{ cursor: "default" }}
className={CS.cursorDefault}
>{t`Hide these`}</Text>
</Menu.Target>
<Menu.Dropdown>
Expand All @@ -68,7 +70,7 @@ export const EmbedHomepageView = (props: EmbedHomepageViewProps) => {
<Card px="xl" py="lg">
{/* eslint-disable-next-line no-literal-metabase-strings -- only visible to admins */}
<Title order={2} mb="md">{t`Embedding Metabase`}</Title>
<Tabs defaultValue={defaultTab}>
<Tabs defaultValue={initialTab}>
<Tabs.List>
<Tabs.Tab value="interactive">{t`Interactive`}</Tabs.Tab>
<Tabs.Tab value="static">{t`Static`}</Tabs.Tab>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { Link } from "react-router";
import { t, jt } from "ttag";
import _ from "underscore";

import ExternalLink from "metabase/core/components/ExternalLink";
import { Anchor, Button, Icon, Text, List } from "metabase/ui";

import type { EmbedHomepageViewProps } from "./EmbedHomepageView";
import { trackEmbeddingHomepageQuickstartClick } from "./analytics";

export const InteractiveTabContent = ({
embeddingAutoEnabled,
interactiveEmbeddingQuickstartUrl,
exampleDashboardId,
licenseActiveAtSetup,
learnMoreInteractiveEmbedUrl,
initialTab,
}: EmbedHomepageViewProps) => {
return (
<>
Expand Down Expand Up @@ -55,7 +58,12 @@ export const InteractiveTabContent = ({
<List.Item>{t`Customize the look and feel of your application to match your brand.`}</List.Item>
</List>

<ExternalLink href={interactiveEmbeddingQuickstartUrl}>
<ExternalLink
href={interactiveEmbeddingQuickstartUrl}
// ExternalLink stops clicks events by default
onClickCapture={_.noop}
onClick={() => trackEmbeddingHomepageQuickstartClick(initialTab)}
>
<Button
variant="filled"
mb="sm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { isNotNull } from "metabase/lib/types";
import { Anchor, Button, Icon, Text, List } from "metabase/ui";

import type { EmbedHomepageViewProps } from "./EmbedHomepageView";
import { trackEmbeddingHomepageExampleDashboardClick } from "./analytics";

export const StaticTabContent = ({
embeddingAutoEnabled,
exampleDashboardId,
learnMoreStaticEmbedUrl,
initialTab,
}: EmbedHomepageViewProps) => {
return (
<>
Expand Down Expand Up @@ -43,7 +45,12 @@ export const StaticTabContent = ({
</List>

{isNotNull(exampleDashboardId) && (
<Link to={`/dashboard/${exampleDashboardId}`}>
<Link
onClick={() =>
trackEmbeddingHomepageExampleDashboardClick(initialTab)
}
to={`/dashboard/${exampleDashboardId}`}
>
<Button
variant="filled"
mb="sm"
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/metabase/home/components/EmbedHomepage/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { updateSetting } from "metabase/admin/settings/settings";
import { createAsyncThunk } from "metabase/lib/redux";
import type { EmbeddingHomepageDismissReason } from "metabase-types/api";

import { trackEmbeddingHomepageDismissed } from "./analytics";

export const dismissEmbeddingHomepage = createAsyncThunk(
"metabase/embedding-homepage/dismiss",
async (reason: EmbeddingHomepageDismissReason, { dispatch }) => {
dispatch(updateSetting({ key: "embedding-homepage", value: reason }));
trackEmbeddingHomepageDismissed(reason);
},
);
34 changes: 34 additions & 0 deletions frontend/src/metabase/home/components/EmbedHomepage/analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { trackSchemaEvent } from "metabase/lib/analytics";
import type { EmbeddingHomepageDismissReason } from "metabase-types/api";

import type { EmbeddingHomepageInitialTab } from "./types";

const SCHEMA_NAME = "embedding_homepage";
const SCHEMA_VERSION = "1-0-0";

export const trackEmbeddingHomepageDismissed = (
dismiss_reason: EmbeddingHomepageDismissReason,
) => {
trackSchemaEvent(SCHEMA_NAME, SCHEMA_VERSION, {
event: "embedding_homepage_dismissed",
dismiss_reason,
});
};

export const trackEmbeddingHomepageQuickstartClick = (
initial_tab: EmbeddingHomepageInitialTab,
) => {
trackSchemaEvent(SCHEMA_NAME, SCHEMA_VERSION, {
event: "embedding_homepage_quickstart_click",
initial_tab,
});
};

export const trackEmbeddingHomepageExampleDashboardClick = (
initial_tab: EmbeddingHomepageInitialTab,
) => {
trackSchemaEvent(SCHEMA_NAME, SCHEMA_VERSION, {
event: "embedding_homepage_example_dashboard_click",
initial_tab,
});
};
Loading

0 comments on commit 5550010

Please sign in to comment.