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

connect settings to the embed homepage and show it #40528

Merged
merged 4 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 : undefined}
key={args.plan}
key={args.defaultTab}
/>
);
},
args: {
embeddingAutoEnabled: true,
hasExampleDashboard: true,
licenseActiveAtSetup: true,
plan: "oss-starter",
defaultTab: "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,6 +1,10 @@
import { useMemo } from "react";

import { useSetting } from "metabase/common/hooks";
import { getPlan } from "metabase/common/utils/plan";
import { useSelector } from "metabase/lib/redux";
import { getDocsUrl } from "metabase/selectors/settings";
import { isEEBuild } from "metabase/lib/utils";
import { getDocsUrl, getSetting } from "metabase/selectors/settings";

import { EmbedHomepageView } from "./EmbedHomepageView";

Expand Down Expand Up @@ -30,12 +34,25 @@ export const EmbedHomepage = () => {
getDocsUrl(state, { page: "embedding/static-embedding" }),
);

const plan = useSelector(state =>
getPlan(getSetting(state, "token-features")),
);

const defaultTab = 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()) {
return plan === "starter" ? "static" : "interactive";
Copy link
Member Author

Choose a reason for hiding this comment

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

Small note: we want to show interactive even if there is no license active, the content of the card will prompt to activate the license. That's why I'm checking if it's a ee build and not if the plan is ee on line 44

}
return "static";
}, [plan]);

return (
<EmbedHomepageView
exampleDashboardId={exampleDashboardId}
embeddingAutoEnabled={embeddingAutoEnabled}
licenseActiveAtSetup={licenseActiveAtSetup}
plan="oss-starter"
defaultTab={defaultTab}
Copy link
Member Author

Choose a reason for hiding this comment

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

I changed the prop here, I think the extra abstraction wasn't worth it, the plan was only used to determine the default tab

interactiveEmbeddingQuickstartUrl={interactiveEmbeddingQuickStartUrl}
embeddingDocsUrl={embeddingDocsUrl}
// eslint-disable-next-line no-unconditional-metabase-links-render -- only visible to admins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type EmbedHomepageViewProps = {
embeddingAutoEnabled: boolean;
exampleDashboardId?: number;
licenseActiveAtSetup: boolean;
plan: "oss-starter" | "pro-ee";
defaultTab: "interactive" | "static";
// links
interactiveEmbeddingQuickstartUrl: string;
embeddingDocsUrl: string;
Expand All @@ -21,8 +21,12 @@ export type EmbedHomepageViewProps = {
};

export const EmbedHomepageView = (props: EmbedHomepageViewProps) => {
const { embeddingAutoEnabled, plan, embeddingDocsUrl, analyticsDocsUrl } =
props;
const {
embeddingAutoEnabled,
defaultTab,
embeddingDocsUrl,
analyticsDocsUrl,
} = props;
return (
<Stack maw={550}>
<Group>
Expand All @@ -32,7 +36,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={plan === "oss-starter" ? "static" : "interactive"}>
<Tabs defaultValue={defaultTab}>
<Tabs.List>
<Tabs.Tab value="interactive">{t`Interactive`}</Tabs.Tab>
<Tabs.Tab value="static">{t`Static`}</Tabs.Tab>
Expand All @@ -57,14 +61,14 @@ export const EmbedHomepageView = (props: EmbedHomepageViewProps) => {
<Text color="text-light" size="sm">
{/* eslint-disable-next-line no-literal-metabase-strings -- only visible to admins */}
{jt`Because you expressed interest in embedding Metabase, we took this step for you so that you can more easily try it out. You can turn it off anytime in ${(
<Link
to="admin/settings/embedding-in-other-applications"
<Anchor
Copy link
Member Author

Choose a reason for hiding this comment

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

Changed from Link > Anchor to <Anchor component={Link} to address warning about nested a tags

size="sm"
component={Link}
to="/admin/settings/embedding-in-other-applications"
key="link"
>
<Anchor size="sm">
admin/settings/embedding-in-other-applications
</Anchor>
</Link>
admin/settings/embedding-in-other-applications
</Anchor>
)}.`}
</Text>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ export const InteractiveTabContent = ({
style={{ listStyleType: "decimal" }}
>
{!licenseActiveAtSetup && (
<>
<List.Item>
<Link to="/admin/settings/license">
<Anchor size="sm">{t`Activate your commercial license`}</Anchor>
</Link>
</List.Item>
</>
<List.Item>
<Anchor
Copy link
Member Author

@npretto npretto Mar 25, 2024

Choose a reason for hiding this comment

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

This change is to avoid the warning about nested tags, same for following Link > Anchors in the next files

size="sm"
component={Link}
to="/admin/settings/license"
>{t`Activate your commercial license`}</Anchor>
</List.Item>
)}
{embeddingAutoEnabled === false && (
<>
<List.Item>
<Link to="/admin/settings/embedding-in-other-applications">
<Anchor size="sm">{t`Enable embedding in the settings`}</Anchor>
</Link>
</List.Item>
</>
<List.Item>
<Anchor
size="sm"
component={Link}
to="/admin/settings/embedding-in-other-applications"
>{t`Enable embedding in the settings`}</Anchor>
</List.Item>
)}
{exampleDashboardId === undefined && (
<List.Item>{t`Create a dashboard to be embedded`}</List.Item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ export const StaticTabContent = ({
>
{embeddingAutoEnabled === false && (
<List.Item>
<Link to="/admin/settings/embedding-in-other-applications">
<Anchor size="sm">{t`Enable embedding in the settings`}</Anchor>
</Link>
<Anchor
size="sm"
component={Link}
to="/admin/settings/embedding-in-other-applications"
>{t`Enable embedding in the settings`}</Anchor>
</List.Item>
)}
<List.Item>{jt`${
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { screen } from "__support__/ui";

import { setup } from "./setup";

describe("EmbedHomepage (OSS)", () => {
it("should default to the static tab for OSS builds", () => {
setup();
expect(
screen.getByText("Use static embedding", { exact: false }),
).toBeInTheDocument();

// making sure Tabs isn't just rendering both tabs, making the test always pass
expect(
screen.queryByText("Use interactive embedding", { exact: false }),
).not.toBeInTheDocument();
});

it("should link to the docs", () => {
setup();
expect(screen.getByText("Learn more")).toHaveAttribute(
"href",
"https://www.metabase.com/docs/latest/embedding/static-embedding.html",
);
});

it("should prompt to enable embedding if it wasn't auto enabled", () => {
setup({ settings: { "setup-embedding-autoenabled": false } });

expect(
screen.getByText("Enable embedding in the settings"),
).toBeInTheDocument();

expect(
screen.queryByText("Embedding has been automatically enabled for you"),
).not.toBeInTheDocument();
});

it("should not prompt to enable embedding if it was auto enabled", () => {
setup({ settings: { "setup-embedding-autoenabled": true } });

expect(
screen.queryByText("Enable embedding in the settings"),
).not.toBeInTheDocument();

expect(
screen.getByText("Embedding has been automatically enabled for you"),
).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { screen } from "__support__/ui";

import type { SetupOpts } from "./setup";
import { setup } from "./setup";

const setupEnterprise = (opts?: SetupOpts) => {
setup({
...opts,
hasEnterprisePlugins: true,
});
};

describe("EmbedHomepage (EE, no token)", () => {
it("should default to the interactive tab for EE builds", () => {
setupEnterprise();
expect(
screen.getByText("Use interactive embedding", { exact: false }),
).toBeInTheDocument();

// making sure Tabs isn't just rendering both tabs, making the test always pass
expect(
screen.queryByText("Use static embedding", { exact: false }),
).not.toBeInTheDocument();
});

it("should prompt to activate the license if it wasn't found at the end of the setup", () => {
setupEnterprise();

expect(
screen.getByText("Activate your commercial license"),
).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { screen } from "__support__/ui";

import type { SetupOpts } from "./setup";
import { setup } from "./setup";

const setupPremium = (opts?: SetupOpts) => {
setup({
...opts,
hasEnterprisePlugins: true,
tokenFeatures: {
embedding: true,
},
});
};

describe("EmbedHomepage (EE, with features)", () => {
it("should default to the interactive tab for EE builds", () => {
setupPremium();
expect(
screen.getByText("Use interactive embedding", { exact: false }),
).toBeInTheDocument();

// making sure Tabs isn't just rendering both tabs, making the test always pass
expect(
screen.queryByText("Use static embedding", { exact: false }),
).not.toBeInTheDocument();
});

it("should prompt to activate the license if it wasn't found at the end of the setup", () => {
setupPremium();

expect(
screen.getByText("Activate your commercial license"),
).toBeInTheDocument();
});

it("should not prompt to activate the license if a license was found at the end of the setup", () => {
setupPremium({
settings: { "setup-license-active-at-setup": true },
});

expect(
screen.queryByText("Activate your commercial license"),
).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { setupEnterprisePlugins } from "__support__/enterprise";
import { renderWithProviders } from "__support__/ui";
import type { Settings, TokenFeatures } from "metabase-types/api";
import { createMockTokenFeatures } from "metabase-types/api/mocks";
import {
createMockSettingsState,
createMockState,
} from "metabase-types/store/mocks";

import { EmbedHomepage } from "../EmbedHomepage";

export interface SetupOpts {
tokenFeatures?: Partial<TokenFeatures>;
hasEnterprisePlugins?: boolean;
settings?: Partial<Settings>;
}

export async function setup({
tokenFeatures = createMockTokenFeatures(),
hasEnterprisePlugins = false,
settings = {},
}: SetupOpts = {}) {
jest.clearAllMocks();

const state = createMockState({
settings: createMockSettingsState({
"token-features": createMockTokenFeatures(tokenFeatures),
...settings,
}),
});

if (hasEnterprisePlugins) {
setupEnterprisePlugins();
}

renderWithProviders(<EmbedHomepage />, { storeInitialState: state });
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
useDatabaseListQuery,
usePopularItemListQuery,
useRecentItemListQuery,
useSetting,
} from "metabase/common/hooks";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
import { useSelector } from "metabase/lib/redux";
Expand All @@ -12,12 +13,14 @@ import type { PopularItem, RecentItem, User } from "metabase-types/api";

import { getIsXrayEnabled } from "../../selectors";
import { isWithinWeeks } from "../../utils";
import { EmbedHomepage } from "../EmbedHomepage";
import { HomePopularSection } from "../HomePopularSection";
import { HomeRecentSection } from "../HomeRecentSection";
import { HomeXraySection } from "../HomeXraySection";

export const HomeContent = (): JSX.Element | null => {
const user = useSelector(getUser);
const embeddingHomepage = useSetting("embedding-homepage");
const isXrayEnabled = useSelector(getIsXrayEnabled);
const { data: databases, error: databasesError } = useDatabaseListQuery();
const { data: recentItems, error: recentItemsError } = useRecentItemListQuery(
Expand All @@ -35,6 +38,10 @@ export const HomeContent = (): JSX.Element | null => {
return <LoadingAndErrorWrapper loading />;
}

if (embeddingHomepage === "visible" && user.is_superuser) {
return <EmbedHomepage />;
}

if (isPopularSection(user, recentItems, popularItems)) {
return <HomePopularSection />;
}
Expand Down
Loading
Loading