Skip to content
Snippets Groups Projects
Unverified Commit dd6916ef authored by Ryan Laurie's avatar Ryan Laurie Committed by GitHub
Browse files

useSetting hook (#39183)

* add useSetting hook

* example usage

* better types

* more implementations
parent edf55f52
No related branches found
No related tags found
No related merge requests found
Showing
with 107 additions and 35 deletions
import { jt, t } from "ttag";
import { useSetting } from "metabase/common/hooks";
import ExternalLink from "metabase/core/components/ExternalLink";
import { isSameOrigin } from "metabase/lib/dom";
import { useSelector } from "metabase/lib/redux";
import { isEmpty } from "metabase/lib/utils";
import { getDocsUrl, getSetting } from "metabase/selectors/settings";
import { getDocsUrl } from "metabase/selectors/settings";
import { Box, Center, Stack, Text } from "metabase/ui";
import { SameSiteAlert } from "./EmbeddingAppSameSiteCookieDescription.styled";
......@@ -18,12 +19,8 @@ export const EmbeddingAppSameSiteCookieDescription = () => {
}),
);
const embeddingSameSiteCookieSetting = useSelector(state =>
getSetting(state, "session-cookie-samesite"),
);
const embeddingAuthorizedOrigins = useSelector(state =>
getSetting(state, "embedding-app-origin"),
);
const embeddingSameSiteCookieSetting = useSetting("session-cookie-samesite");
const embeddingAuthorizedOrigins = useSetting("embedding-app-origin");
const shouldDisplayNote =
embeddingSameSiteCookieSetting !== "none" &&
......
import { Link } from "react-router";
import { jt, t } from "ttag";
import { useSetting } from "metabase/common/hooks";
import { getPlan } from "metabase/common/utils/plan";
import ExternalLink from "metabase/core/components/ExternalLink";
import { useSelector } from "metabase/lib/redux";
......@@ -51,7 +52,7 @@ function EmbeddingOption({
}
export const StaticEmbeddingOptionCard = () => {
const enabled = useSelector(state => getSetting(state, "enable-embedding"));
const enabled = useSetting("enable-embedding");
const upgradeUrl = useSelector(state =>
getUpgradeUrl(state, { utm_media: "embed-settings" }),
);
......@@ -91,7 +92,7 @@ export const InteractiveEmbeddingOptionCard = () => {
const plan = useSelector(state =>
getPlan(getSetting(state, "token-features")),
);
const enabled = useSelector(state => getSetting(state, "enable-embedding"));
const enabled = useSetting("enable-embedding");
const quickStartUrl = useSelector(state =>
getDocsUrlForVersion(
getSetting(state, "version"),
......
......@@ -3,11 +3,12 @@ import { useMount } from "react-use";
import { t } from "ttag";
import _ from "underscore";
import { useSetting } from "metabase/common/hooks";
import AdminHeader from "metabase/components/AdminHeader";
import Code from "metabase/components/Code";
import { CopyButton } from "metabase/components/CopyButton";
import { useSelector } from "metabase/lib/redux";
import { getIsPaidPlan, getSetting } from "metabase/selectors/settings";
import { getIsPaidPlan } from "metabase/selectors/settings";
import { UtilApi } from "metabase/services";
import {
......@@ -91,7 +92,7 @@ const InfoBlock = ({ children }: InfoBlockProps) => (
export const Help = () => {
const [details, setDetails] = useState({ "browser-info": navigatorInfo() });
const { tag } = useSelector(state => getSetting(state, "version"));
const { tag } = useSetting("version");
const isPaidPlan = useSelector(getIsPaidPlan);
useMount(async () => {
......
......@@ -24,3 +24,5 @@ export * from "./use-table-list-query";
export * from "./use-table-metadata-query";
export * from "./use-table-query";
export * from "./use-user-query";
export * from "./use-setting";
export * from "./use-setting";
import { useSelector } from "metabase/lib/redux";
import { getSetting } from "metabase/selectors/settings";
import type { Settings } from "metabase-types/api";
export const useSetting = <SettingName extends keyof Settings>(
settingName: SettingName,
) => {
return useSelector(state => getSetting(state, settingName));
};
import { renderWithProviders, screen } from "__support__/ui";
import type { Settings } from "metabase-types/api";
import { useSetting } from "./use-setting";
const TestComponent = ({ settingName }: { settingName: keyof Settings }) => {
const settingValue = useSetting(settingName);
return (
<div>
<div>{JSON.stringify(settingValue)}</div>
<div>{typeof settingValue}</div>
<div>{Array.isArray(settingValue) && "isArray"}</div>
<div>{settingValue === null && "isNull"}</div>
</div>
);
};
describe("useTableListQuery", () => {
it("should get a string setting", async () => {
renderWithProviders(<TestComponent settingName={"admin-email"} />);
expect(screen.getByText('"admin@metabase.test"')).toBeInTheDocument();
expect(screen.getByText("string")).toBeInTheDocument();
});
it("should get a number setting", async () => {
renderWithProviders(
<TestComponent settingName={"query-caching-min-ttl"} />,
);
expect(screen.getByText("60")).toBeInTheDocument();
expect(screen.getByText("number")).toBeInTheDocument();
});
it("should get a boolean setting", async () => {
renderWithProviders(<TestComponent settingName={"ldap-enabled"} />);
expect(screen.getByText("false")).toBeInTheDocument();
expect(screen.getByText("boolean")).toBeInTheDocument();
});
it("should get an object setting", async () => {
renderWithProviders(<TestComponent settingName={"password-complexity"} />);
expect(screen.getByText('{"total":6,"digit":1}')).toBeInTheDocument();
expect(screen.getByText("object")).toBeInTheDocument();
});
it("should get an array setting", async () => {
renderWithProviders(<TestComponent settingName={"available-fonts"} />);
expect(screen.getByText("[]")).toBeInTheDocument();
expect(screen.getByText("object")).toBeInTheDocument();
expect(screen.getByText("isArray")).toBeInTheDocument();
});
it("should get an empty setting", async () => {
renderWithProviders(<TestComponent settingName={"uploads-schema-name"} />);
expect(screen.getByText("null")).toBeInTheDocument();
expect(screen.getByText("object")).toBeInTheDocument();
expect(screen.getByText("isNull")).toBeInTheDocument();
});
it("typescript should detect fake settings", async () => {
// @ts-expect-error - testing expected error for bad keys
renderWithProviders(<TestComponent settingName={"my-fake-setting"} />);
expect(screen.getByText("undefined")).toBeInTheDocument();
});
});
import type { Location } from "history";
import { useSetting } from "metabase/common/hooks";
import { useSelector } from "metabase/lib/redux";
import { DatabasePromptBanner } from "metabase/nav/components/DatabasePromptBanner";
import {
PaymentBanner,
shouldRenderPaymentBanner,
} from "metabase/nav/components/PaymentBanner/PaymentBanner";
import { getSetting } from "metabase/selectors/settings";
import { getUserIsAdmin } from "metabase/selectors/user";
interface AppBannerProps {
......@@ -15,7 +15,7 @@ interface AppBannerProps {
export const AppBanner = ({ location }: AppBannerProps) => {
const isAdmin = useSelector(getUserIsAdmin);
const tokenStatus = useSelector(state => getSetting(state, "token-status"));
const tokenStatus = useSetting("token-status");
if (tokenStatus && shouldRenderPaymentBanner({ isAdmin, tokenStatus })) {
return <PaymentBanner isAdmin={isAdmin} tokenStatus={tokenStatus} />;
}
......
import type { Location } from "history";
import { t } from "ttag";
import { useSetting } from "metabase/common/hooks";
import Link from "metabase/core/components/Link/Link";
import { useSelector } from "metabase/lib/redux";
import { trackDatabasePromptBannerClicked } from "metabase/nav/analytics";
import { useShouldShowDatabasePromptBanner } from "metabase/nav/hooks";
import { getSetting } from "metabase/selectors/settings";
import {
ConnectDatabaseButton,
......@@ -20,8 +19,8 @@ interface DatabasePromptBannerProps {
}
export function DatabasePromptBanner({ location }: DatabasePromptBannerProps) {
const adminEmail = useSelector(state => getSetting(state, "admin-email"));
const siteUrl = useSelector(state => getSetting(state, "site-url"));
const adminEmail = useSetting("admin-email");
const siteUrl = useSetting("site-url");
const helpUrl = new URL("https://metabase.com/help/connect");
helpUrl.searchParams.set("email", adminEmail || "");
......
......@@ -5,6 +5,7 @@ import { t } from "ttag";
import _ from "underscore";
import { getAdminPaths } from "metabase/admin/app/selectors";
import { useSetting } from "metabase/common/hooks";
import EntityMenu from "metabase/components/EntityMenu";
import LogoIcon from "metabase/components/LogoIcon";
import Modal from "metabase/components/Modal";
......@@ -12,7 +13,6 @@ import { color } from "metabase/lib/colors";
import { capitalize } from "metabase/lib/formatting";
import { useSelector } from "metabase/lib/redux";
import * as Urls from "metabase/lib/urls";
import { getSetting } from "metabase/selectors/settings";
import {
getApplicationName,
getIsWhiteLabeling,
......@@ -30,7 +30,7 @@ export default connect(mapStateToProps)(ProfileLink);
function ProfileLink({ adminItems, onLogout }) {
const [modalOpen, setModalOpen] = useState(null);
const version = useSelector(state => getSetting(state, "version"));
const version = useSetting("version");
const applicationName = useSelector(getApplicationName);
const { tag, date, ...versionExtra } = version;
const helpLink = useHelpLink();
......
import { useEffect, useState } from "react";
import { useSetting } from "metabase/common/hooks";
import { useSelector } from "metabase/lib/redux";
import { getSetting, getIsPaidPlan } from "metabase/selectors/settings";
import { getIsPaidPlan } from "metabase/selectors/settings";
import { UtilApi } from "metabase/services";
import { getUser } from "../../../selectors/user";
export const useHelpLink = (): { visible: boolean; href: string } => {
const helpLinkSetting = useSelector(state => getSetting(state, "help-link"));
const helpLinkCustomDestinationSetting = useSelector(state =>
getSetting(state, "help-link-custom-destination"),
const helpLinkSetting = useSetting("help-link");
const helpLinkCustomDestinationSetting = useSetting(
"help-link-custom-destination",
);
const [bugReportDetails, setBugReportDetails] = useState(null);
const user = useSelector(getUser);
const isAdmin = user?.is_superuser;
const isPaidPlan = useSelector(getIsPaidPlan);
const version = useSelector(state => getSetting(state, "version"));
const version = useSetting("version");
const compactBugReportDetailsForUrl = encodeURIComponent(
JSON.stringify(bugReportDetails),
......
......@@ -2,10 +2,10 @@ import { useCallback, useMemo } from "react";
import { t } from "ttag";
import { updateSetting } from "metabase/admin/settings/settings";
import { useSetting } from "metabase/common/hooks";
import { color } from "metabase/lib/colors";
import { useDispatch, useSelector } from "metabase/lib/redux";
import { getIsEmbedded } from "metabase/selectors/embed";
import { getSetting } from "metabase/selectors/settings";
import { getIsWhiteLabeling } from "metabase/selectors/whitelabel";
import { Icon, Anchor, Flex, Paper, Stack, Text } from "metabase/ui";
......@@ -16,11 +16,9 @@ import { getLatestEligibleReleaseNotes } from "./utils";
export function WhatsNewNotification() {
const dispatch = useDispatch();
const isEmbedded = useSelector(getIsEmbedded);
const versionInfo = useSelector(state => getSetting(state, "version-info"));
const currentVersion = useSelector(state => getSetting(state, "version"));
const lastAcknowledgedVersion = useSelector(state =>
getSetting(state, "last-acknowledged-version"),
);
const versionInfo = useSetting("version-info");
const currentVersion = useSetting("version");
const lastAcknowledgedVersion = useSetting("last-acknowledged-version");
const isWhiteLabeling = useSelector(getIsWhiteLabeling);
const url: string | undefined = useMemo(() => {
......
......@@ -2,6 +2,7 @@ import { useMemo, useState } from "react";
import { t } from "ttag";
import _ from "underscore";
import { useSetting } from "metabase/common/hooks";
import { useSelector } from "metabase/lib/redux";
import { checkNotNull } from "metabase/lib/types";
import {
......@@ -24,7 +25,6 @@ import type {
EmbedResourceParameter,
EmbedResourceType,
} from "metabase/public/lib/types";
import { getSetting } from "metabase/selectors/settings";
import { getCanWhitelabel } from "metabase/selectors/whitelabel";
import { Stack, Tabs } from "metabase/ui";
import { getParameterValue } from "metabase-lib/parameters/utils/parameter-values";
......@@ -73,10 +73,8 @@ export const StaticEmbedSetupPane = ({
}: StaticEmbedSetupPaneProps): JSX.Element => {
const [activePane, setActivePane] = useState<ActivePreviewPane>("code");
const siteUrl = useSelector(state => getSetting(state, "site-url"));
const secretKey = checkNotNull(
useSelector(state => getSetting(state, "embedding-secret-key")),
);
const siteUrl = useSetting("site-url");
const secretKey = checkNotNull(useSetting("embedding-secret-key"));
const initialEmbeddingParams = getDefaultEmbeddingParams(
resource,
resourceParameters,
......
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