Skip to content
Snippets Groups Projects
Unverified Commit eaf1e80d authored by Nicolò Pretto's avatar Nicolò Pretto Committed by GitHub
Browse files

refactor DashboardControls (#44558)

* WIP PublicOrCustomEmbedDashboardPage without using dashboard controls

* add usePublicDashboardEndpoints instead of WithPublicDashboardEndpoints

* fix type error by setting null as default value for hide_parameters and hide_download_button

* use usePublicDashboardEndpoints inside WithPublicDashboardEndpoints

* also migrate embed

* i don't think we need useDashboardNav public/static embed

* SetTitle component to use instead of the `title` hoc

* wrap setEmbedDashboardEndpoints/setPublicDashboardEndpoints in useEffect as per PR comment

* after the fix for metabase#38640 we don't need the public routes in the main app

* renamed test file

* change tests to use PublicOrEmbeddedDashboardPage

* remove PublicOrEmbeddedDashboardControlled and change imports for PublicOrEmbeddedDashboardPage

* remove debug prop left by mistake
parent e7e4fd6f
No related branches found
No related tags found
No related merge requests found
import PropTypes from "prop-types";
import { Component, cloneElement } from "react";
import { Route as _Route } from "react-router";
import _ from "underscore";
......@@ -75,6 +76,19 @@ const title = documentTitleOrGetter => ComposedComponent =>
export default title;
/**
* Component version of the title HOC
* @param {string} props.title
*/
export const SetTitle = props => {
const Component = title(props.title)(() => null);
return <Component />;
};
SetTitle.propTypes = {
title: PropTypes.string,
};
// react-router Route wrapper that adds a `title` property
export class Route extends _Route {
static createRouteFromReactElement(element) {
......
import type { Query } from "history";
import { type ComponentType, Component } from "react";
import { Component } from "react";
import type { ConnectedProps } from "react-redux";
import { connect } from "react-redux";
import _ from "underscore";
......@@ -13,12 +13,11 @@ import {
setParameterValueToDefault,
} from "metabase/dashboard/actions";
import type { NavigateToNewCardFromDashboardOpts } from "metabase/dashboard/components/DashCard/types";
import { DashboardControls } from "metabase/dashboard/hoc/DashboardControls";
import {
getDashboardComplete,
getDraftParameterValues,
getParameters,
getParameterValues,
getParameters,
getSelectedTabId,
getSlowCards,
} from "metabase/dashboard/selectors";
......@@ -28,10 +27,8 @@ import type {
FetchDashboardResult,
SuccessfulFetchDashboardResult,
} from "metabase/dashboard/types";
import title from "metabase/hoc/Title";
import { WithPublicDashboardEndpoints } from "metabase/public/containers/PublicOrEmbeddedDashboard/WithPublicDashboardEndpoints";
import { setErrorPage } from "metabase/redux/app";
import type { Dashboard, DashboardId } from "metabase-types/api";
import type { DashboardId } from "metabase-types/api";
import type { State } from "metabase-types/store";
import { PublicOrEmbeddedDashboardView } from "./PublicOrEmbeddedDashboardView";
......@@ -213,13 +210,3 @@ function isSuccessfulFetchDashboardResult(
export const PublicOrEmbeddedDashboard = connector(
PublicOrEmbeddedDashboardInner,
);
// PublicDashboardControlled used for embedding with location
// Uses DashboardControls to handle display options, and uses WithPublicDashboardEndpoints to set endpoints for public/embed contexts
export const PublicOrEmbeddedDashboardControlled = _.compose(
title(
({ dashboard }: { dashboard: Dashboard }) => dashboard && dashboard.name,
),
WithPublicDashboardEndpoints,
DashboardControls,
)(PublicOrEmbeddedDashboard) as ComponentType<OwnProps>;
import type { WithRouterProps } from "react-router";
import { useSyncURLSlug } from "metabase/dashboard/components/DashboardTabs/use-sync-url-slug";
import {
useDashboardUrlParams,
useRefreshDashboard,
} from "metabase/dashboard/hooks";
import { getDashboardComplete } from "metabase/dashboard/selectors";
import { SetTitle } from "metabase/hoc/Title";
import { useSelector } from "metabase/lib/redux";
import { PublicOrEmbeddedDashboard } from "./PublicOrEmbeddedDashboard";
import { usePublicDashboardEndpoints } from "./WithPublicDashboardEndpoints";
export const PublicOrEmbeddedDashboardPage = (props: WithRouterProps) => {
const { location } = props;
const parameterQueryParams = props.location.query;
const { dashboardId } = usePublicDashboardEndpoints(props);
const { refreshDashboard } = useRefreshDashboard({
dashboardId,
parameterQueryParams,
});
const {
bordered,
hasNightModeToggle,
hideDownloadButton,
hideParameters,
isFullscreen,
isNightMode,
onNightModeChange,
refreshPeriod,
onFullscreenChange,
setRefreshElapsedHook,
onRefreshPeriodChange,
theme,
titled,
font,
} = useDashboardUrlParams({ location, onRefresh: refreshDashboard });
useSyncURLSlug({ location });
const dashboard = useSelector(getDashboardComplete);
return (
<>
<SetTitle title={dashboard?.name} />
<PublicOrEmbeddedDashboard
dashboardId={dashboardId}
isFullscreen={isFullscreen}
refreshPeriod={refreshPeriod}
hideParameters={hideParameters}
isNightMode={isNightMode}
hasNightModeToggle={hasNightModeToggle}
setRefreshElapsedHook={setRefreshElapsedHook}
onNightModeChange={onNightModeChange}
onFullscreenChange={onFullscreenChange}
onRefreshPeriodChange={onRefreshPeriodChange}
bordered={bordered}
hideDownloadButton={hideDownloadButton}
theme={theme}
titled={titled}
font={font}
parameterQueryParams={parameterQueryParams}
cardTitled={true}
/>
</>
);
};
......@@ -16,13 +16,13 @@ import {
} from "metabase-types/api/mocks";
import { createMockState } from "metabase-types/store/mocks";
import { PublicOrEmbeddedDashboardControlled } from "./PublicOrEmbeddedDashboard";
import { PublicOrEmbeddedDashboardPage } from "./PublicOrEmbeddedDashboardPage";
const MOCK_TOKEN =
"eyJhbGciOiJIUzI1NiJ9.eyJyZXNvdXJjZSI6eyJkYXNoYm9hcmQiOjExfSwicGFyYW1zIjp7fSwiaWF0IjoxNzEyNjg0NTA1LCJfZW1iZWRkaW5nX3BhcmFtcyI6e319.WbZTB-cQYh4gjh61ZzoLOcFbJ6j6RlOY3GS4fwzv3W4";
const DASHBOARD_TITLE = '"My test dash"';
describe("PublicOrEmbeddedDashboard", () => {
describe("PublicOrEmbeddedDashboardPage", () => {
it("should display dashboard tabs", async () => {
await setup({ numberOfTabs: 2 });
......@@ -135,7 +135,7 @@ async function setup({
renderWithProviders(
<Route
path="embed/dashboard/:token"
component={PublicOrEmbeddedDashboardControlled}
component={PublicOrEmbeddedDashboardPage}
/>,
{
storeInitialState: createMockState(),
......
import type { ComponentType } from "react";
import { useEffect, type ComponentType } from "react";
import type { WithRouterProps } from "react-router";
import {
......@@ -7,26 +7,30 @@ import {
} from "metabase/services";
import type { DashboardId } from "metabase-types/api";
/** @deprecated - prefer `usePublicDashboardEndpoints`*/
export const WithPublicDashboardEndpoints = <T extends WithRouterProps>(
Component: ComponentType<T>,
): ComponentType<T & { dashboardId: DashboardId }> => {
function DashboardEndpointsInner({
params: { uuid, token },
...props
}: {
params: {
uuid?: string;
token?: string;
};
}) {
function DashboardEndpointsInner(props: WithRouterProps) {
const { dashboardId } = usePublicDashboardEndpoints(props);
return <Component {...(props as T)} dashboardId={dashboardId} />;
}
return DashboardEndpointsInner;
};
export const usePublicDashboardEndpoints = (props: WithRouterProps) => {
const { uuid, token } = props.params;
useEffect(() => {
if (uuid) {
setPublicDashboardEndpoints();
} else if (token) {
setEmbedDashboardEndpoints();
}
const dashboardId = uuid || token;
return <Component {...(props as T)} dashboardId={dashboardId} />;
}
}, [uuid, token]);
return DashboardEndpointsInner;
const dashboardId = uuid || token;
return { dashboardId };
};
export { PublicOrEmbeddedDashboardControlled } from "./PublicOrEmbeddedDashboard";
export { PublicOrEmbeddedDashboardPage } from "./PublicOrEmbeddedDashboardPage";
......@@ -2,16 +2,17 @@ import { Route } from "react-router";
import { PublicNotFound } from "metabase/public/components/PublicNotFound";
import PublicApp from "metabase/public/containers/PublicApp";
import { PublicOrEmbeddedDashboardControlled } from "metabase/public/containers/PublicOrEmbeddedDashboard";
import { PublicOrEmbeddedQuestion } from "metabase/public/containers/PublicOrEmbeddedQuestion";
import { PublicOrEmbeddedDashboardPage } from "./public/containers/PublicOrEmbeddedDashboard";
export const getRoutes = store => (
<Route>
<Route path="embed" component={PublicApp}>
<Route path="question/:token" component={PublicOrEmbeddedQuestion} />
<Route
path="dashboard/:token"
component={PublicOrEmbeddedDashboardControlled}
component={PublicOrEmbeddedDashboardPage}
/>
<Route path="*" component={PublicNotFound} />
</Route>
......
......@@ -2,9 +2,9 @@ import { Route } from "metabase/hoc/Title";
import { PublicNotFound } from "metabase/public/components/PublicNotFound";
import PublicAction from "metabase/public/containers/PublicAction";
import PublicApp from "metabase/public/containers/PublicApp";
import { PublicOrEmbeddedDashboardControlled } from "metabase/public/containers/PublicOrEmbeddedDashboard";
import { PublicOrEmbeddedQuestion } from "metabase/public/containers/PublicOrEmbeddedQuestion";
import { PublicOrEmbeddedDashboardPage } from "./public/containers/PublicOrEmbeddedDashboard";
import { getApplicationName } from "./selectors/whitelabel";
export const getRoutes = store => {
......@@ -16,7 +16,7 @@ export const getRoutes = store => {
<Route path="question/:uuid" component={PublicOrEmbeddedQuestion} />
<Route
path="dashboard/:uuid(/:tabSlug)"
component={PublicOrEmbeddedDashboardControlled}
component={PublicOrEmbeddedDashboardPage}
/>
<Route path="*" component={PublicNotFound} />
</Route>
......
......@@ -32,8 +32,6 @@ import ModelMetabotApp from "metabase/metabot/containers/ModelMetabotApp";
import NewModelOptions from "metabase/models/containers/NewModelOptions";
import { getRoutes as getModelRoutes } from "metabase/models/routes";
import { PLUGIN_LANDING_PAGE } from "metabase/plugins";
import { PublicOrEmbeddedDashboardControlled } from "metabase/public/containers/PublicOrEmbeddedDashboard";
import { PublicOrEmbeddedQuestion } from "metabase/public/containers/PublicOrEmbeddedQuestion";
import QueryBuilder from "metabase/query_builder/containers/QueryBuilder";
import { loadCurrentUser } from "metabase/redux/user";
import DatabaseDetailContainer from "metabase/reference/databases/DatabaseDetailContainer";
......@@ -85,15 +83,6 @@ export const getRoutes = store => {
}}
/>
{/* PUBLICLY SHARED LINKS */}
<Route path="public">
<Route path="question/:uuid" component={PublicOrEmbeddedQuestion} />
<Route
path="dashboard/:uuid(/:tabSlug)"
component={PublicOrEmbeddedDashboardControlled}
/>
</Route>
{/* APP */}
<Route
onEnter={async (nextState, replace, done) => {
......
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