From a5a944c41ed030e94080e48efcc21a64c8266e44 Mon Sep 17 00:00:00 2001 From: Alexander Polyankin <alexander.polyankin@metabase.com> Date: Mon, 10 Jul 2023 11:35:49 +0300 Subject: [PATCH] Fix embedding plugins init (#32138) --- .../EmbeddingAppOriginDescription.tsx | 31 +++++++ .../EmbeddingAppOriginDescription/index.ts | 1 + .../metabase-enterprise/embedding/index.js | 81 +++++++------------ frontend/src/metabase/admin/routes.jsx | 4 +- .../SettingsEditor/SettingsEditor.jsx} | 14 ++-- .../app/components/SettingsEditor/index.ts | 1 + .../SettingsEditor/tests/common.unit.spec.tsx | 25 ++++++ .../tests/enterprise.unit.spec.tsx | 32 ++++++++ .../tests/premium.unit.spec.tsx | 39 +++++++++ .../components/SettingsEditor/tests/setup.tsx | 58 +++++++++++++ .../EmbeddingCustomizationInfo.tsx | 33 -------- .../EmbeddingCustomizationInfo/index.ts | 2 - .../EmbeddingCustomizationWidget.tsx | 21 +++++ ...mbeddingCustomizationWidget.unit.spec.tsx} | 6 +- .../EmbeddingCustomizationWidget/index.ts | 1 + .../FullAppEmbeddingLinkWidget.tsx | 24 ++---- .../FullAppEmbeddingLinkWidget.unit.spec.tsx | 2 +- .../FullAppEmbeddingLinkWidget/index.ts | 3 +- .../src/metabase/admin/settings/selectors.js | 28 ++++--- frontend/src/metabase/plugins/index.ts | 4 + frontend/test/__support__/enterprise.js | 7 ++ 21 files changed, 289 insertions(+), 128 deletions(-) create mode 100644 enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/EmbeddingAppOriginDescription.tsx create mode 100644 enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/index.ts rename frontend/src/metabase/admin/settings/{containers/SettingsEditorApp.jsx => app/components/SettingsEditor/SettingsEditor.jsx} (96%) create mode 100644 frontend/src/metabase/admin/settings/app/components/SettingsEditor/index.ts create mode 100644 frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/common.unit.spec.tsx create mode 100644 frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/enterprise.unit.spec.tsx create mode 100644 frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/premium.unit.spec.tsx create mode 100644 frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/setup.tsx delete mode 100644 frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.tsx delete mode 100644 frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/index.ts create mode 100644 frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.tsx rename frontend/src/metabase/admin/settings/components/widgets/{EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.unit.spec.tsx => EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.unit.spec.tsx} (63%) create mode 100644 frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/index.ts diff --git a/enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/EmbeddingAppOriginDescription.tsx b/enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/EmbeddingAppOriginDescription.tsx new file mode 100644 index 00000000000..295660bccab --- /dev/null +++ b/enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/EmbeddingAppOriginDescription.tsx @@ -0,0 +1,31 @@ +import { jt, t } from "ttag"; +import ExternalLink from "metabase/core/components/ExternalLink"; +import MetabaseSettings from "metabase/lib/settings"; + +export const EmbeddingAppOriginDescription = () => { + return ( + <div> + {jt`With this Pro/Enterprise feature you can embed the full Metabase app. Enable your users to drill-through to charts, browse collections, and use the graphical query builder. ${( + <ExternalLink + key="learn-more" + href={MetabaseSettings.learnUrl( + "embedding/multi-tenant-self-service-analytics", + )} + > + {t`Learn more.`} + </ExternalLink> + )}`} + <div className="my4"> + <strong className="block text-dark mb1">{t`Authorized origins`}</strong> + {jt`Enter the origins for the websites or web apps where you want to allow embedding, separated by a space. Here are the ${( + <ExternalLink + key="specs" + href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors" + > + {t`exact specifications`} + </ExternalLink> + )} for what can be entered.`} + </div> + </div> + ); +}; diff --git a/enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/index.ts b/enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/index.ts new file mode 100644 index 00000000000..0c22012cb56 --- /dev/null +++ b/enterprise/frontend/src/metabase-enterprise/embedding/components/EmbeddingAppOriginDescription/index.ts @@ -0,0 +1 @@ +export { EmbeddingAppOriginDescription } from "./EmbeddingAppOriginDescription"; diff --git a/enterprise/frontend/src/metabase-enterprise/embedding/index.js b/enterprise/frontend/src/metabase-enterprise/embedding/index.js index bbeae11f569..e97cad21627 100644 --- a/enterprise/frontend/src/metabase-enterprise/embedding/index.js +++ b/enterprise/frontend/src/metabase-enterprise/embedding/index.js @@ -1,55 +1,34 @@ -import { jt, t } from "ttag"; -import { updateIn } from "icepick"; - -import MetabaseSettings from "metabase/lib/settings"; +import { t } from "ttag"; import { hasPremiumFeature } from "metabase-enterprise/settings"; -import { PLUGIN_ADMIN_SETTINGS_UPDATES } from "metabase/plugins"; -import ExternalLink from "metabase/core/components/ExternalLink"; +import { + PLUGIN_ADMIN_SETTINGS_UPDATES, + PLUGIN_EMBEDDING, +} from "metabase/plugins"; +import { EmbeddingAppOriginDescription } from "./components/EmbeddingAppOriginDescription"; -if (hasPremiumFeature("embedding")) { - MetabaseSettings.hideEmbedBranding = () => true; -} +const SLUG = "embedding-in-other-applications/full-app"; -const APP_ORIGIN_SETTING = { - key: "embedding-app-origin", - display_name: t`Embedding the entire Metabase app`, - description: ( - <> - {jt`With this Pro/Enterprise feature you can embed the full Metabase app. Enable your users to drill-through to charts, browse collections, and use the graphical query builder. ${( - <ExternalLink - key="learn-more" - href={MetabaseSettings.learnUrl( - "embedding/multi-tenant-self-service-analytics", - )} - > - {t`Learn more.`} - </ExternalLink> - )}`} - <div className="my4"> - <strong className="block text-dark mb1">{t`Authorized origins`}</strong> - {jt`Enter the origins for the websites or web apps where you want to allow embedding, separated by a space. Here are the ${( - <ExternalLink - key="specs" - href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors" - > - {t`exact specifications`} - </ExternalLink> - )} for what can be entered.`} - </div> - </> - ), - placeholder: "https://*.example.com", - type: "string", - getHidden: settings => - !settings["enable-embedding"] || !MetabaseSettings.isEnterprise(), -}; +if (hasPremiumFeature("embedding")) { + PLUGIN_EMBEDDING.isEnabled = () => true; -PLUGIN_ADMIN_SETTINGS_UPDATES.push(sections => - updateIn( - sections, - ["embedding-in-other-applications/full-app", "settings"], - settings => { - return [...settings, APP_ORIGIN_SETTING]; - }, - ), -); + PLUGIN_ADMIN_SETTINGS_UPDATES.push(sections => { + return { + ...sections, + [SLUG]: { + ...sections[SLUG], + settings: [ + ...sections[SLUG]["settings"], + { + key: "embedding-app-origin", + display_name: t`Embedding the entire Metabase app`, + description: <EmbeddingAppOriginDescription />, + placeholder: "https://*.example.com", + type: "string", + getHidden: (_, derivedSettings) => + !derivedSettings["enable-embedding"], + }, + ], + }, + }; + }); +} diff --git a/frontend/src/metabase/admin/routes.jsx b/frontend/src/metabase/admin/routes.jsx index 0e0c592a222..786812520cd 100644 --- a/frontend/src/metabase/admin/routes.jsx +++ b/frontend/src/metabase/admin/routes.jsx @@ -27,7 +27,7 @@ import EditUserModal from "metabase/admin/people/containers/EditUserModal"; import UserActivationModal from "metabase/admin/people/containers/UserActivationModal"; // Settings -import SettingsEditorApp from "metabase/admin/settings/containers/SettingsEditorApp"; +import { SettingsEditor } from "metabase/admin/settings/app/components/SettingsEditor"; import PremiumEmbeddingLicensePage from "metabase/admin/settings/containers/PremiumEmbeddingLicensePage"; // DB Add / list @@ -174,7 +174,7 @@ const getRoutes = (store, CanAccessSettings, IsAdmin) => ( path="premium-embedding-license" component={PremiumEmbeddingLicensePage} /> - <Route path="*" component={SettingsEditorApp} /> + <Route path="*" component={SettingsEditor} /> </Route> </Route> diff --git a/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/SettingsEditor.jsx similarity index 96% rename from frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx rename to frontend/src/metabase/admin/settings/app/components/SettingsEditor/SettingsEditor.jsx index 8776d345c13..54c45d29457 100644 --- a/frontend/src/metabase/admin/settings/containers/SettingsEditorApp.jsx +++ b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/SettingsEditor.jsx @@ -16,7 +16,7 @@ import { NotFound } from "metabase/containers/ErrorPages"; import { prepareAnalyticsValue } from "metabase/admin/settings/utils"; import ErrorBoundary from "metabase/ErrorBoundary"; -import SettingsSetting from "../components/SettingsSetting"; +import SettingsSetting from "../../../components/SettingsSetting"; import { getSettings, @@ -26,8 +26,12 @@ import { getActiveSection, getActiveSectionName, getNewVersionAvailable, -} from "../selectors"; -import { initializeSettings, updateSetting, reloadSettings } from "../settings"; +} from "../../../selectors"; +import { + initializeSettings, + updateSetting, + reloadSettings, +} from "../../../settings"; const mapStateToProps = (state, props) => { return { @@ -53,7 +57,7 @@ const mapDispatchToProps = dispatch => ({ dispatch, }); -class SettingsEditorApp extends Component { +class SettingsEditor extends Component { layout = null; // the reference to AdminLayout static propTypes = { @@ -272,4 +276,4 @@ class SettingsEditorApp extends Component { export default _.compose( connect(mapStateToProps, mapDispatchToProps), title(({ activeSection }) => activeSection && activeSection.name), -)(SettingsEditorApp); +)(SettingsEditor); diff --git a/frontend/src/metabase/admin/settings/app/components/SettingsEditor/index.ts b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/index.ts new file mode 100644 index 00000000000..dd18d9993ef --- /dev/null +++ b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/index.ts @@ -0,0 +1 @@ +export { default as SettingsEditor } from "./SettingsEditor"; diff --git a/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/common.unit.spec.tsx b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/common.unit.spec.tsx new file mode 100644 index 00000000000..dadf102edfe --- /dev/null +++ b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/common.unit.spec.tsx @@ -0,0 +1,25 @@ +import { + createMockSettingDefinition, + createMockSettings, +} from "metabase-types/api/mocks"; +import { screen } from "__support__/ui"; +import { setup } from "./setup"; + +const FULL_APP_EMBEDDING_URL = + "/admin/settings/embedding-in-other-applications/full-app"; + +describe("SettingsEditor", () => { + describe("full-app embedding", () => { + it("should show info about full app embedding", async () => { + setup({ + settings: [createMockSettingDefinition({ key: "enable-embedding" })], + settingValues: createMockSettings({ "enable-embedding": true }), + initialRoute: FULL_APP_EMBEDDING_URL, + }); + + expect(await screen.findByText("Full-app embedding")).toBeInTheDocument(); + expect(screen.getByText(/some of our paid plans/)).toBeInTheDocument(); + expect(screen.queryByText("Authorized origins")).not.toBeInTheDocument(); + }); + }); +}); diff --git a/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/enterprise.unit.spec.tsx b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/enterprise.unit.spec.tsx new file mode 100644 index 00000000000..96c15561d6d --- /dev/null +++ b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/enterprise.unit.spec.tsx @@ -0,0 +1,32 @@ +import { + createMockSettingDefinition, + createMockSettings, +} from "metabase-types/api/mocks"; +import { screen } from "__support__/ui"; +import { setup, SetupOpts } from "./setup"; + +const setupEnterprise = (opts?: SetupOpts) => { + setup({ ...opts, hasEnterprisePlugins: true }); +}; + +const FULL_APP_EMBEDDING_URL = + "/admin/settings/embedding-in-other-applications/full-app"; + +describe("SettingsEditor", () => { + describe("full-app embedding", () => { + it("should show info about full app embedding", async () => { + setupEnterprise({ + settings: [ + createMockSettingDefinition({ key: "enable-embedding" }), + createMockSettingDefinition({ key: "embedding-app-origin" }), + ], + settingValues: createMockSettings({ "enable-embedding": true }), + initialRoute: FULL_APP_EMBEDDING_URL, + }); + + expect(await screen.findByText("Full-app embedding")).toBeInTheDocument(); + expect(screen.getByText(/some of our paid plans/)).toBeInTheDocument(); + expect(screen.queryByText("Authorized origins")).not.toBeInTheDocument(); + }); + }); +}); diff --git a/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/premium.unit.spec.tsx b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/premium.unit.spec.tsx new file mode 100644 index 00000000000..e6344fd6534 --- /dev/null +++ b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/premium.unit.spec.tsx @@ -0,0 +1,39 @@ +import { + createMockSettingDefinition, + createMockSettings, + createMockTokenFeatures, +} from "metabase-types/api/mocks"; +import { screen } from "__support__/ui"; +import { setup, SetupOpts } from "./setup"; + +const setupPremium = (opts?: SetupOpts) => { + setup({ + ...opts, + tokenFeatures: createMockTokenFeatures({ embedding: true }), + hasEnterprisePlugins: true, + }); +}; + +const FULL_APP_EMBEDDING_URL = + "/admin/settings/embedding-in-other-applications/full-app"; + +describe("SettingsEditor", () => { + describe("full-app embedding", () => { + it("should allow to configure the origin for full-app embedding", async () => { + setupPremium({ + settings: [ + createMockSettingDefinition({ key: "enable-embedding" }), + createMockSettingDefinition({ key: "embedding-app-origin" }), + ], + settingValues: createMockSettings({ "enable-embedding": true }), + initialRoute: FULL_APP_EMBEDDING_URL, + }); + + expect(await screen.findByText("Full-app embedding")).toBeInTheDocument(); + expect(screen.getByText("Authorized origins")).toBeInTheDocument(); + expect( + screen.queryByText(/some of our paid plans/), + ).not.toBeInTheDocument(); + }); + }); +}); diff --git a/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/setup.tsx b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/setup.tsx new file mode 100644 index 00000000000..0f5bb85a42f --- /dev/null +++ b/frontend/src/metabase/admin/settings/app/components/SettingsEditor/tests/setup.tsx @@ -0,0 +1,58 @@ +/* istanbul ignore file */ +import { IndexRedirect, Route } from "react-router"; +import { SettingDefinition, Settings, TokenFeatures } from "metabase-types/api"; +import { + createMockSettings, + createMockTokenFeatures, +} from "metabase-types/api/mocks"; +import { createMockState } from "metabase-types/store/mocks"; +import { setupEnterprisePlugins } from "__support__/enterprise"; +import { + setupPropertiesEndpoints, + setupSettingsEndpoints, +} from "__support__/server-mocks"; +import { mockSettings } from "__support__/settings"; +import { renderWithProviders } from "__support__/ui"; +import SettingsEditor from "../SettingsEditor"; + +export interface SetupOpts { + initialRoute?: string; + settings?: SettingDefinition[]; + settingValues?: Settings; + tokenFeatures?: TokenFeatures; + hasEnterprisePlugins?: boolean; +} + +export const setup = ({ + initialRoute = "/admin/settings", + settings = [], + settingValues = createMockSettings(), + tokenFeatures = createMockTokenFeatures(), + hasEnterprisePlugins = false, +}: SetupOpts = {}) => { + const state = createMockState({ + settings: mockSettings({ + ...settingValues, + "token-features": tokenFeatures, + }), + }); + + if (hasEnterprisePlugins) { + setupEnterprisePlugins(); + } + + setupSettingsEndpoints(settings); + setupPropertiesEndpoints(settingValues); + + renderWithProviders( + <Route path="/admin/settings"> + <IndexRedirect to="general" /> + <Route path="*" component={SettingsEditor} /> + </Route>, + { + storeInitialState: state, + withRouter: true, + initialRoute, + }, + ); +}; diff --git a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.tsx b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.tsx deleted file mode 100644 index 863ffbae168..00000000000 --- a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { connect } from "react-redux"; -import { t, jt } from "ttag"; -import ExternalLink from "metabase/core/components/ExternalLink"; -import { getUpgradeUrl } from "metabase/selectors/settings"; -import { State } from "metabase-types/store"; -import SettingHeader from "../../SettingHeader"; - -interface StateProps { - upgradeUrl: string; -} - -type EmbeddingCustomizationInfoProps = StateProps; - -const mapStateToProps = (state: State): StateProps => ({ - upgradeUrl: getUpgradeUrl(state, { utm_media: "embed_standalone" }), -}); - -const EmbeddingCustomizationInfo = ({ - upgradeUrl, -}: EmbeddingCustomizationInfoProps) => { - const setting = { - description: jt`In order to remove the Metabase logo from embeds, you can always upgrade to ${( - <ExternalLink key="upgrade-link" href={upgradeUrl}> - {t`one of our paid plans.`} - </ExternalLink> - )}`, - }; - - return <SettingHeader id="embedding-customization-info" setting={setting} />; -}; - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default connect(mapStateToProps)(EmbeddingCustomizationInfo); diff --git a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/index.ts b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/index.ts deleted file mode 100644 index 60d840d1189..00000000000 --- a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./EmbeddingCustomizationInfo"; diff --git a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.tsx b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.tsx new file mode 100644 index 00000000000..e074f92b82f --- /dev/null +++ b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.tsx @@ -0,0 +1,21 @@ +import { jt, t } from "ttag"; +import { useSelector } from "metabase/lib/redux"; +import { getUpgradeUrl } from "metabase/selectors/settings"; +import ExternalLink from "metabase/core/components/ExternalLink"; +import SettingHeader from "../../SettingHeader"; + +export const EmbeddingCustomizationWidget = () => { + const upgradeUrl = useSelector(state => + getUpgradeUrl(state, { utm_media: "embed_standalone" }), + ); + + const setting = { + description: jt`In order to remove the Metabase logo from embeds, you can always upgrade to ${( + <ExternalLink key="upgrade-link" href={upgradeUrl}> + {t`one of our paid plans.`} + </ExternalLink> + )}`, + }; + + return <SettingHeader id="embedding-customization-info" setting={setting} />; +}; diff --git a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.unit.spec.tsx b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.unit.spec.tsx similarity index 63% rename from frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.unit.spec.tsx rename to frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.unit.spec.tsx index c0fde1dcfdb..18be5a9e76d 100644 --- a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationInfo/EmbeddingCustomizationInfo.unit.spec.tsx +++ b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/EmbeddingCustomizationWidget.unit.spec.tsx @@ -1,11 +1,11 @@ import { renderWithProviders, screen } from "__support__/ui"; -import EmbeddingCustomizationInfo from "./EmbeddingCustomizationInfo"; +import { EmbeddingCustomizationWidget } from "./EmbeddingCustomizationWidget"; const setup = () => { - renderWithProviders(<EmbeddingCustomizationInfo />); + renderWithProviders(<EmbeddingCustomizationWidget />); }; -describe("EmbeddingCustomizationInfo", () => { +describe("EmbeddingCustomizationWidget", () => { it("should add utm_media to the upgrade link", () => { setup(); diff --git a/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/index.ts b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/index.ts new file mode 100644 index 00000000000..7b60db353b6 --- /dev/null +++ b/frontend/src/metabase/admin/settings/components/widgets/EmbeddingCustomizationWidget/index.ts @@ -0,0 +1 @@ +export { EmbeddingCustomizationWidget } from "./EmbeddingCustomizationWidget"; diff --git a/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.tsx b/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.tsx index 13435825fe8..75b72dddafe 100644 --- a/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.tsx +++ b/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.tsx @@ -1,23 +1,14 @@ -import { connect } from "react-redux"; import { jt, t } from "ttag"; -import ExternalLink from "metabase/core/components/ExternalLink"; +import { useSelector } from "metabase/lib/redux"; import { getUpgradeUrl } from "metabase/selectors/settings"; -import { State } from "metabase-types/store"; +import ExternalLink from "metabase/core/components/ExternalLink"; import SettingHeader from "../../SettingHeader"; -interface StateProps { - upgradeUrl: string; -} - -type FullAppEmbeddingLinkWidgetProps = StateProps; +export const FullAppEmbeddingLinkWidget = () => { + const upgradeUrl = useSelector(state => + getUpgradeUrl(state, { utm_media: "embed_fullapp" }), + ); -const mapStateToProps = (state: State): StateProps => ({ - upgradeUrl: getUpgradeUrl(state, { utm_media: "embed_fullapp" }), -}); - -const FullAppEmbeddingLinkWidget = ({ - upgradeUrl, -}: FullAppEmbeddingLinkWidgetProps) => { const setting = { display_name: t`embedding the entire metabase app`, description: jt`With ${( @@ -29,6 +20,3 @@ const FullAppEmbeddingLinkWidget = ({ return <SettingHeader id="embedding-customization-info" setting={setting} />; }; - -// eslint-disable-next-line import/no-default-export -- deprecated usage -export default connect(mapStateToProps)(FullAppEmbeddingLinkWidget); diff --git a/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.unit.spec.tsx b/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.unit.spec.tsx index 998f8a2bf8f..3ba7216a97b 100644 --- a/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.unit.spec.tsx +++ b/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/FullAppEmbeddingLinkWidget.unit.spec.tsx @@ -1,5 +1,5 @@ import { renderWithProviders, screen } from "__support__/ui"; -import FullAppEmbeddingLinkWidget from "./FullAppEmbeddingLinkWidget"; +import { FullAppEmbeddingLinkWidget } from "./FullAppEmbeddingLinkWidget"; const setup = () => { renderWithProviders(<FullAppEmbeddingLinkWidget />); diff --git a/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/index.ts b/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/index.ts index 75e642ed5cc..e00852d69bd 100644 --- a/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/index.ts +++ b/frontend/src/metabase/admin/settings/components/widgets/FullAppEmbeddingLinkWidget/index.ts @@ -1,2 +1 @@ -// eslint-disable-next-line import/no-default-export -- deprecated usage -export { default } from "./FullAppEmbeddingLinkWidget"; +export { FullAppEmbeddingLinkWidget } from "./FullAppEmbeddingLinkWidget"; diff --git a/frontend/src/metabase/admin/settings/selectors.js b/frontend/src/metabase/admin/settings/selectors.js index f924278a212..e8a6f670e38 100644 --- a/frontend/src/metabase/admin/settings/selectors.js +++ b/frontend/src/metabase/admin/settings/selectors.js @@ -5,7 +5,10 @@ import ExternalLink from "metabase/core/components/ExternalLink"; import MetabaseSettings from "metabase/lib/settings"; import { PersistedModelsApi, UtilApi } from "metabase/services"; -import { PLUGIN_ADMIN_SETTINGS_UPDATES } from "metabase/plugins"; +import { + PLUGIN_ADMIN_SETTINGS_UPDATES, + PLUGIN_EMBEDDING, +} from "metabase/plugins"; import { getUserIsAdmin } from "metabase/selectors/user"; import Breadcrumbs from "metabase/components/Breadcrumbs"; import { DashboardSelector } from "metabase/components/DashboardSelector"; @@ -18,7 +21,7 @@ import { UploadSettings } from "./components/UploadSettings"; import SettingsLicense from "./components/SettingsLicense"; import SiteUrlWidget from "./components/widgets/SiteUrlWidget"; import HttpsOnlyWidget from "./components/widgets/HttpsOnlyWidget"; -import EmbeddingCustomizationInfo from "./components/widgets/EmbeddingCustomizationInfo"; +import { EmbeddingCustomizationWidget } from "./components/widgets/EmbeddingCustomizationWidget"; import { PublicLinksDashboardListing, PublicLinksQuestionListing, @@ -29,7 +32,7 @@ import { import SecretKeyWidget from "./components/widgets/SecretKeyWidget"; import EmbeddingLegalese from "./components/widgets/EmbeddingLegalese"; import FormattingWidget from "./components/widgets/FormattingWidget"; -import FullAppEmbeddingLinkWidget from "./components/widgets/FullAppEmbeddingLinkWidget"; +import { FullAppEmbeddingLinkWidget } from "./components/widgets/FullAppEmbeddingLinkWidget"; import ModelCachingScheduleWidget from "./components/widgets/ModelCachingScheduleWidget"; import SectionDivider from "./components/widgets/SectionDivider"; @@ -67,7 +70,7 @@ function updateSectionsWithPlugins(sections) { } } -const SECTIONS = updateSectionsWithPlugins({ +const SECTIONS = { setup: { name: t`Setup`, order: 10, @@ -521,10 +524,9 @@ const SECTIONS = updateSectionsWithPlugins({ getHidden: (_, derivedSettings) => !derivedSettings["enable-embedding"], }, { - widget: EmbeddingCustomizationInfo, + widget: EmbeddingCustomizationWidget, getHidden: (_, derivedSettings) => - !derivedSettings["enable-embedding"] || - MetabaseSettings.isEnterprise(), + !derivedSettings["enable-embedding"] || PLUGIN_EMBEDDING.isEnabled(), }, { widget: () => ( @@ -555,8 +557,7 @@ const SECTIONS = updateSectionsWithPlugins({ { widget: FullAppEmbeddingLinkWidget, getHidden: (_, derivedSettings) => - !derivedSettings["enable-embedding"] || - MetabaseSettings.isEnterprise(), + !derivedSettings["enable-embedding"] || PLUGIN_EMBEDDING.isEnabled(), }, { widget: () => ( @@ -702,7 +703,11 @@ const SECTIONS = updateSectionsWithPlugins({ }, ], }, -}); +}; + +const getSectionsWithPlugins = _.once(() => + updateSectionsWithPlugins(SECTIONS), +); export const getSettings = createSelector( state => state.admin.settings.settings, @@ -741,9 +746,10 @@ export const getSections = createSelector( return {}; } + const sections = getSectionsWithPlugins(); const settingsByKey = _.groupBy(settings, "key"); const sectionsWithAPISettings = {}; - for (const [slug, section] of Object.entries(SECTIONS)) { + for (const [slug, section] of Object.entries(sections)) { const isHidden = section.getHidden?.(derivedSettingValues); if (isHidden || (section.adminOnly && !isAdmin)) { diff --git a/frontend/src/metabase/plugins/index.ts b/frontend/src/metabase/plugins/index.ts index 60c8a96dc2c..2f47681eb44 100644 --- a/frontend/src/metabase/plugins/index.ts +++ b/frontend/src/metabase/plugins/index.ts @@ -281,3 +281,7 @@ export const PLUGIN_MODEL_PERSISTENCE = { ModelCacheControl: PluginPlaceholder as any, getMenuItems: (question?: any, onChange?: any) => ({}), }; + +export const PLUGIN_EMBEDDING = { + isEnabled: () => false, +}; diff --git a/frontend/test/__support__/enterprise.js b/frontend/test/__support__/enterprise.js index e28e6514798..7b6082b0f4b 100644 --- a/frontend/test/__support__/enterprise.js +++ b/frontend/test/__support__/enterprise.js @@ -1,7 +1,14 @@ +/** + * @deprecated use setupEnterprisePlugins with settings set via mockSettings + */ export function setupEnterpriseTest() { jest.mock("metabase-enterprise/settings", () => ({ hasPremiumFeature: jest.fn().mockReturnValue(true), })); + setupEnterprisePlugins(); +} + +export function setupEnterprisePlugins() { require("metabase-enterprise/plugins"); } -- GitLab