Skip to content
Snippets Groups Projects
Unverified Commit 9a840f92 authored by Mahatthana (Kelvin) Nomsawadi's avatar Mahatthana (Kelvin) Nomsawadi Committed by GitHub
Browse files

Add show metabase links toggle admin setting (#37076)


* Add show metabase links toggle admin setting

* Hide Metabase links

* Fix type error

* Add selector tests

* Hide a link in HomeHelpCard

* Make test names more consistent with existing test suites

* Add tests to `NewModelOptions`

* Prepare `VisualizationError` for testing

* Add tests to `VisualizationError`

* Hide link and add tests to `PreviewQueryModal`

* Extract components to make it easier to test

* Move the new component into its own folder

* Hide Metabase link in `ActionDashcardSettings`

* Prepare `EmptyFormPlaceholder` for testing

* Hide Metabase link in `EmptyFormPlaceholder`

* Extract Metabase link from `FormCreator` for testing

* Hide Metabase link in `FormCreator`

* Extract link from `DashCardCardParameterMapper` to prepare for testing

* Hide Metabase link in `DashCardParameterMapper`

* Clean up the test setup function

* Hide Metabase link in `ExpressionEditorHelpText`

* Hide Metabase link in `TagEditorHelp`

* Hide Metabase links in `MetricList`

* Hide Metabase link in `SegmentList`

* Prepare `CaveatMessage` for testing

* Hide Metabase link in `CaveatMessage`

* Hide Metabase link in `CustomMapFooter`

* Hide Metabase link in `ImpossibleToCreateModelModal`

* Hide Metabase link in `ExpressionWidget`

* Hide Metabase link in `ExpressionWidget`

* Add BE tests

* Update sample database description

* Fix TypeScript type-check

* Fix failed unit tests

* Fix wrong test names

* Add missing translations

* Make tests looks like tests from other components

* Update enterprise/frontend/src/metabase-enterprise/whitelabel/components/MetabaseLinksToggleWidget/MetabaseLinksToggleWidget.tsx

Co-authored-by: default avatarNicolò Pretto <info@npretto.com>

* Simplify the change

* Fix weird import directory

* Fix wrapped translation copy

* Fix test name

* Move comment next to the component

* Fix test names

* Review: Make code easier to review

* Fix wrong document link

* Update src/metabase/public_settings.clj

Co-authored-by: default avatarNoah Moss <32746338+noahmoss@users.noreply.github.com>

* Update src/metabase/public_settings.clj

Co-authored-by: default avatarNoah Moss <32746338+noahmoss@users.noreply.github.com>

* Address review: BE changes

---------

Co-authored-by: default avatarNicolò Pretto <info@npretto.com>
Co-authored-by: default avatarNoah Moss <32746338+noahmoss@users.noreply.github.com>
parent b8b42945
No related branches found
No related tags found
No related merge requests found
Showing
with 307 additions and 26 deletions
......@@ -25,3 +25,7 @@ export const getIsWhiteLabeling = (state: EnterpriseState) =>
export function getApplicationName(state: EnterpriseState) {
return getSetting(state, "application-name");
}
export function getShowMetabaseLinks(state: EnterpriseState) {
return getSetting(state, "show-metabase-links");
}
import { t, jt } from "ttag";
import { Anchor, Popover, Stack, Text } from "metabase/ui";
export function MetabaseLinksToggleDescription() {
return jt`Control the visibility of links to Metabase documentation and Metabase references in your instance. ${(
<Popover key="popover" position="top-start">
<Popover.Target>
<Anchor style={{ userSelect: "none", cursor: "pointer" }}>
{t`Learn more`}
</Anchor>
</Popover.Target>
<Popover.Dropdown>
<Stack p="md" spacing="sm" maw={420}>
<Text size="sm">
{t`This affects all links in the product experience (outside of the admin panel) that point to Metabase.com URLs.`}
</Text>
<Text size="sm">
{t`When hidden, your users will lose the ability to troubleshoot and learn how to use features such as the Query and SQL Editors, among others.`}
</Text>
<Text size="sm">
{t`You might also want to customize the Application Name setting.`}
</Text>
</Stack>
</Popover.Dropdown>
</Popover>
)}`;
}
import { t } from "ttag";
import { Switch } from "metabase/ui";
interface MetabaseLinksToggleSetting {
value: boolean | null;
default: boolean;
}
interface MetabaseLinksToggleWidgetProps {
setting: MetabaseLinksToggleSetting;
onChange: (value: boolean) => void;
}
export function MetabaseLinksToggleWidget({
setting,
onChange,
}: MetabaseLinksToggleWidgetProps) {
return (
<Switch
checked={setting.value ?? setting.default}
onChange={e => onChange(e.target.checked)}
labelPosition="left"
label={t`Show links and references`}
size="sm"
/>
);
}
export { MetabaseLinksToggleWidget } from "./MetabaseLinksToggleWidget";
export { MetabaseLinksToggleDescription } from "./MetabaseLinksToggleDescription";
......@@ -12,6 +12,7 @@ import {
getApplicationName,
getIsWhiteLabeling,
getLoadingMessage,
getShowMetabaseLinks,
} from "metabase-enterprise/settings/selectors";
import MetabaseSettings from "metabase/lib/settings";
......@@ -27,6 +28,10 @@ import LogoIcon from "./components/LogoIcon";
import { updateColors } from "./lib/whitelabel";
import { getLoadingMessageOptions } from "./lib/loading-message";
import { HelpLinkSettings } from "./components/HelpLinkSettings";
import {
MetabaseLinksToggleDescription,
MetabaseLinksToggleWidget,
} from "./components/MetabaseLinksToggleWidget";
if (hasPremiumFeature("whitelabel")) {
PLUGIN_LANDING_PAGE.push(() => MetabaseSettings.get("landing-page"));
......@@ -108,6 +113,12 @@ if (hasPremiumFeature("whitelabel")) {
widget: LighthouseToggleWidget,
defaultValue: true,
},
{
key: "show-metabase-links",
display_name: t`Documentation and references`,
description: <MetabaseLinksToggleDescription />,
widget: MetabaseLinksToggleWidget,
},
],
},
...sections,
......@@ -125,4 +136,5 @@ if (hasPremiumFeature("whitelabel")) {
PLUGIN_SELECTORS.getLoadingMessage = getLoadingMessage;
PLUGIN_SELECTORS.getIsWhiteLabeling = getIsWhiteLabeling;
PLUGIN_SELECTORS.getApplicationName = getApplicationName;
PLUGIN_SELECTORS.getShowMetabaseLinks = getShowMetabaseLinks;
}
......@@ -200,6 +200,7 @@ export const createMockSettings = (
"show-homepage-pin-message": false,
"show-homepage-xrays": false,
"show-lighthouse-illustration": true,
"show-metabase-links": true,
"show-metabot": true,
"site-locale": "en",
"site-url": "http://localhost:3000",
......
......@@ -258,6 +258,7 @@ export interface Settings {
"show-homepage-pin-message": boolean;
"show-homepage-xrays": boolean;
"show-lighthouse-illustration": boolean;
"show-metabase-links": boolean;
"show-metabot": boolean;
"site-locale": string;
"site-uuid": string;
......
......@@ -3,8 +3,6 @@ import styled from "@emotion/styled";
import { space } from "metabase/styled-components/theme";
import { color } from "metabase/lib/colors";
import ExternalLink from "metabase/core/components/ExternalLink";
export const ActionSettingsWrapper = styled.div`
display: flex;
height: 80vh;
......@@ -81,15 +79,3 @@ export const ModalActions = styled.div`
padding: 1rem;
border-top: 1px solid ${color("border")};
`;
export const ExplainerText = styled.p`
margin-left: ${space(3)};
margin-right: ${space(3)};
color: ${color("text-medium")};
`;
export const BrandLinkWithLeftMargin = styled(ExternalLink)`
margin-left: ${space(1)};
color: ${color("brand")};
`;
......@@ -5,8 +5,6 @@ import { useMemo } from "react";
import Button from "metabase/core/components/Button";
import EmptyState from "metabase/components/EmptyState";
import MetabaseSettings from "metabase/lib/settings";
import { ConnectedActionPicker } from "metabase/actions/containers/ActionPicker";
import { setActionForDashcard } from "metabase/dashboard/actions";
......@@ -27,14 +25,13 @@ import {
ActionSettingsLeft,
ActionSettingsRight,
ModalActions,
ExplainerText,
BrandLinkWithLeftMargin,
} from "./ActionDashcardSettings.styled";
import {
getParameterDefaultValue,
isParameterHidden,
isParameterRequired,
} from "./utils";
import { ExplainerText } from "./ExplainerText";
const mapDispatchToProps = {
setActionForDashcard,
......@@ -101,14 +98,7 @@ export function ActionDashcardSettings({
<ActionSettingsHeader>
{t`Where should the values for '${action.name}' come from?`}
</ActionSettingsHeader>
<ExplainerText>
{t`You can either ask users to enter values, or use the value of a dashboard filter.`}
<BrandLinkWithLeftMargin
href={MetabaseSettings.docsUrl("dashboards/actions")}
>
{t`Learn more.`}
</BrandLinkWithLeftMargin>
</ExplainerText>
<ExplainerText />
</>
)}
<ParameterMapperContainer>
......
import styled from "@emotion/styled";
import { space } from "metabase/styled-components/theme";
import { color } from "metabase/lib/colors";
import ExternalLink from "metabase/core/components/ExternalLink";
export const ExplainerTextContainer = styled.p`
margin-left: ${space(3)};
margin-right: ${space(3)};
color: ${color("text-medium")};
`;
export const BrandLinkWithLeftMargin = styled(ExternalLink)`
margin-left: ${space(1)};
color: ${color("brand")};
`;
import { t } from "ttag";
import MetabaseSettings from "metabase/lib/settings";
import { useSelector } from "metabase/lib/redux";
import { getShowMetabaseLinks } from "metabase/selectors/whitelabel";
import {
ExplainerTextContainer,
BrandLinkWithLeftMargin,
} from "./ExplainerText.styled";
export function ExplainerText() {
const showMetabaseLinks = useSelector(getShowMetabaseLinks);
return (
<ExplainerTextContainer>
{t`You can either ask users to enter values, or use the value of a dashboard filter.`}
{showMetabaseLinks && (
<BrandLinkWithLeftMargin
href={MetabaseSettings.docsUrl("dashboards/actions")}
>
{t`Learn more.`}
</BrandLinkWithLeftMargin>
)}
</ExplainerTextContainer>
);
}
export { ExplainerText } from "./ExplainerText";
import { screen } from "__support__/ui";
import { setup } from "./setup";
describe("ExplainerText (OSS)", () => {
it("should render help link when `show-metabase-links: true`", () => {
setup({ showMetabaseLinks: true });
expect(
screen.getByText(
"You can either ask users to enter values, or use the value of a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.getByText("Learn more.")).toBeInTheDocument();
});
it("should render help link when `show-metabase-links: false`", () => {
setup({ showMetabaseLinks: false });
expect(
screen.getByText(
"You can either ask users to enter values, or use the value of a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.getByText("Learn more.")).toBeInTheDocument();
});
});
import { screen } from "__support__/ui";
import { setup as baseSetup } from "./setup";
import type { SetupOpts } from "./setup";
function setup(opts: SetupOpts) {
baseSetup({ hasEnterprisePlugins: true, ...opts });
}
describe("ExplainerText (EE without token)", () => {
it("should render help link when `show-metabase-links: true`", () => {
setup({ showMetabaseLinks: true });
expect(
screen.getByText(
"You can either ask users to enter values, or use the value of a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.getByText("Learn more.")).toBeInTheDocument();
});
it("should render help link when `show-metabase-links: false`", () => {
setup({ showMetabaseLinks: false });
expect(
screen.getByText(
"You can either ask users to enter values, or use the value of a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.getByText("Learn more.")).toBeInTheDocument();
});
});
import { screen } from "__support__/ui";
import { setup as baseSetup } from "./setup";
import type { SetupOpts } from "./setup";
function setup(opts: SetupOpts) {
baseSetup({
hasEnterprisePlugins: true,
tokenFeatures: { whitelabel: true },
...opts,
});
}
describe("ExplainerText (EE with token)", () => {
it("should render help link when `show-metabase-links: true`", () => {
setup({ showMetabaseLinks: true });
expect(
screen.getByText(
"You can either ask users to enter values, or use the value of a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.getByText("Learn more.")).toBeInTheDocument();
});
it("should not render help link when `show-metabase-links: false`", () => {
setup({ showMetabaseLinks: false });
expect(
screen.getByText(
"You can either ask users to enter values, or use the value of a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.queryByText("Learn more.")).not.toBeInTheDocument();
});
});
import type { TokenFeatures } from "metabase-types/api";
import { createMockTokenFeatures } from "metabase-types/api/mocks";
import { createMockState } from "metabase-types/store/mocks";
import { setupEnterprisePlugins } from "__support__/enterprise";
import { mockSettings } from "__support__/settings";
import { renderWithProviders } from "__support__/ui";
import { ExplainerText } from "../ExplainerText";
export interface SetupOpts {
showMetabaseLinks?: boolean;
hasEnterprisePlugins?: boolean;
tokenFeatures?: Partial<TokenFeatures>;
}
export const setup = ({
showMetabaseLinks = true,
hasEnterprisePlugins,
tokenFeatures = {},
}: SetupOpts = {}) => {
const state = createMockState({
settings: mockSettings({
"show-metabase-links": showMetabaseLinks,
"token-features": createMockTokenFeatures(tokenFeatures),
}),
});
if (hasEnterprisePlugins) {
setupEnterprisePlugins();
}
renderWithProviders(<ExplainerText />, { storeInitialState: state });
};
import styled from "@emotion/styled";
import { color } from "metabase/lib/colors";
export const InfoText = styled.div`
color: ${color("text-medium")};
`;
import { jt, t } from "ttag";
import ExternalLink from "metabase/core/components/ExternalLink";
import { useSelector } from "metabase/lib/redux";
import { getDocsUrl } from "metabase/selectors/settings";
import { getShowMetabaseLinks } from "metabase/selectors/whitelabel";
import { InfoText } from "./Description.styled";
export function Description() {
const docsLink = useSelector(state =>
getDocsUrl(state, { page: "actions/custom" }),
);
const showMetabaseLinks = useSelector(getShowMetabaseLinks);
return (
<InfoText>
{jt`Configure your parameters' types and properties here. The values for these parameters can come from user input, or from a dashboard filter.`}
{showMetabaseLinks && (
<>
{" "}
<ExternalLink
key="learn-more"
href={docsLink}
>{t`Learn more`}</ExternalLink>
</>
)}
</InfoText>
);
}
export { Description } from "./Description";
import { screen } from "__support__/ui";
import { setup } from "./setup";
describe("FormCerator > Description (OSS)", () => {
it("should show a help link when `show-metabase-links: true`", () => {
setup({ showMetabaseLinks: true });
expect(
screen.getByText(
"Configure your parameters' types and properties here. The values for these parameters can come from user input, or from a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.getByText("Learn more")).toBeInTheDocument();
});
it("should show a help link when `show-metabase-links: false`", () => {
setup({ showMetabaseLinks: false });
expect(
screen.getByText(
"Configure your parameters' types and properties here. The values for these parameters can come from user input, or from a dashboard filter.",
),
).toBeInTheDocument();
expect(screen.getByText("Learn more")).toBeInTheDocument();
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment