From b6e6e07c9eb9da3495763d251ff05d410436a059 Mon Sep 17 00:00:00 2001
From: Nick Fitzpatrick <nick@metabase.com>
Date: Thu, 23 Jun 2022 16:49:39 -0300
Subject: [PATCH] Adding breadcumbs for Dashboards (#23489)

---
 .../src/metabase/nav/containers/AppBar.tsx    | 13 +++++-----
 .../query_builder/containers/QueryBuilder.jsx | 18 +-------------
 frontend/src/metabase/redux/app.js            | 22 -----------------
 frontend/src/metabase/selectors/app.ts        | 24 +++++++++++++++----
 4 files changed, 27 insertions(+), 50 deletions(-)

diff --git a/frontend/src/metabase/nav/containers/AppBar.tsx b/frontend/src/metabase/nav/containers/AppBar.tsx
index 2f7e46b7e2e..00ac215df82 100644
--- a/frontend/src/metabase/nav/containers/AppBar.tsx
+++ b/frontend/src/metabase/nav/containers/AppBar.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo, useState } from "react";
+import React, { useCallback, useMemo, useState, ReactNode } from "react";
 import { t } from "ttag";
 import _ from "underscore";
 import { connect } from "react-redux";
@@ -18,8 +18,9 @@ import { getIsNavbarOpen, closeNavbar, toggleNavbar } from "metabase/redux/app";
 import {
   getIsNewButtonVisible,
   getIsSearchVisible,
-  getBreadcrumbCollectionId,
+  getCollectionId,
   getShowBreadcumb,
+  RouterProps,
 } from "metabase/selectors/app";
 import { isMac } from "metabase/lib/browser";
 import { isSmallScreen } from "metabase/lib/dom";
@@ -47,13 +48,13 @@ type Props = {
   closeNavbar: () => void;
 };
 
-function mapStateToProps(state: State) {
+function mapStateToProps(state: State, props: RouterProps) {
   return {
     isNavBarOpen: getIsNavbarOpen(state),
     isSearchVisible: getIsSearchVisible(state),
     isNewButtonVisible: getIsNewButtonVisible(state),
-    collectionId: getBreadcrumbCollectionId(state),
-    showBreadcrumb: getShowBreadcumb(state),
+    collectionId: getCollectionId(state),
+    showBreadcrumb: getShowBreadcumb(state, props),
   };
 }
 
@@ -76,9 +77,9 @@ function AppBar({
   isSearchVisible,
   isNewButtonVisible,
   collectionId,
-  showBreadcrumb,
   toggleNavbar,
   closeNavbar,
+  showBreadcrumb,
 }: Props) {
   const [isSearchActive, setSearchActive] = useState(false);
 
diff --git a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
index a818c82fc35..5b756b00814 100644
--- a/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
+++ b/frontend/src/metabase/query_builder/containers/QueryBuilder.jsx
@@ -16,11 +16,7 @@ import Bookmark from "metabase/entities/bookmarks";
 import Collections from "metabase/entities/collections";
 import Timelines from "metabase/entities/timelines";
 
-import {
-  closeNavbar,
-  setCollectionId,
-  clearBreadcrumbs,
-} from "metabase/redux/app";
+import { closeNavbar } from "metabase/redux/app";
 import { MetabaseApi } from "metabase/services";
 import { getMetadata } from "metabase/selectors/metadata";
 import {
@@ -206,8 +202,6 @@ const mapStateToProps = (state, props) => {
 
 const mapDispatchToProps = {
   ...actions,
-  setCollectionId,
-  clearBreadcrumbs,
   closeNavbar,
   onChangeLocation: push,
   createBookmark: id => Bookmark.actions.create({ id, type: "card" }),
@@ -240,8 +234,6 @@ function QueryBuilder(props) {
     showTimelinesForCollection,
     card,
     isLoadingComplete,
-    setCollectionId,
-    clearBreadcrumbs,
   } = props;
 
   const forceUpdate = useForceUpdate();
@@ -256,14 +248,6 @@ function QueryBuilder(props) {
   const wasNativeEditorOpen = usePrevious(isNativeEditorOpen);
   const hasQuestion = question != null;
   const collectionId = question?.collectionId();
-  const isSaved = question?.isSaved();
-
-  useEffect(() => {
-    if (isSaved) {
-      setCollectionId(collectionId);
-      return () => clearBreadcrumbs();
-    }
-  }, [collectionId, isSaved, setCollectionId, clearBreadcrumbs]);
 
   const openModal = useCallback(
     (modal, modalContext) => setUIControls({ modal, modalContext }),
diff --git a/frontend/src/metabase/redux/app.js b/frontend/src/metabase/redux/app.js
index 5c58bdea273..831fbea9562 100644
--- a/frontend/src/metabase/redux/app.js
+++ b/frontend/src/metabase/redux/app.js
@@ -72,29 +72,7 @@ const isNavbarOpen = handleActions(
   checkIsSidebarInitiallyOpen(),
 );
 
-export const SET_COLLECTION_ID = "metabase/app/SET_COLLECTION_ID";
-export const CLEAR_BREADCRUMBS = "metabase/app/CLEAR_BREADCRUMBS";
-export const setCollectionId = createAction(SET_COLLECTION_ID);
-export const clearBreadcrumbs = createAction(CLEAR_BREADCRUMBS);
-const defaultBreadcumbsState = {
-  collectionId: "",
-  show: false,
-};
-
-const breadcrumbs = handleActions(
-  {
-    [SET_COLLECTION_ID]: {
-      next: (_state, { payload }) => ({ show: true, collectionId: payload }),
-    },
-    [CLEAR_BREADCRUMBS]: {
-      next: () => ({ show: false, collectionId: undefined }),
-    },
-  },
-  defaultBreadcumbsState,
-);
-
 export default combineReducers({
   errorPage,
   isNavbarOpen,
-  breadcrumbs,
 });
diff --git a/frontend/src/metabase/selectors/app.ts b/frontend/src/metabase/selectors/app.ts
index e54f03ccea4..949e89f2ae7 100644
--- a/frontend/src/metabase/selectors/app.ts
+++ b/frontend/src/metabase/selectors/app.ts
@@ -1,11 +1,15 @@
 import { Location } from "history";
 import { createSelector } from "reselect";
 import { getUser } from "metabase/selectors/user";
-import { getIsEditing as getIsEditingDashboard } from "metabase/dashboard/selectors";
+import {
+  getIsEditing as getIsEditingDashboard,
+  getDashboard,
+} from "metabase/dashboard/selectors";
+import { getQuestion } from "metabase/query_builder/selectors";
 import { getEmbedOptions, getIsEmbedded } from "metabase/selectors/embed";
 import { State } from "metabase-types/store";
 
-interface RouterProps {
+export interface RouterProps {
   location: Location;
 }
 
@@ -16,6 +20,11 @@ const EMBEDDED_PATHS_WITH_NAVBAR = [
   /^\/collection\/.*/,
   /^\/archive/,
 ];
+const PATHS_WITH_COLLECTION_BREADCRUMBS = [
+  /\/question\//,
+  /\/model\//,
+  /\/dashboard\//,
+];
 
 export const getRouterPath = (state: State, props: RouterProps) => {
   return props.location.pathname;
@@ -107,7 +116,12 @@ export const getErrorMessage = (state: State) => {
   return errorPage?.data?.message || errorPage?.data;
 };
 
-export const getBreadcrumbCollectionId = (state: State) =>
-  state.app.breadcrumbs.collectionId;
+export const getShowBreadcumb = createSelector([getRouterPath], path =>
+  PATHS_WITH_COLLECTION_BREADCRUMBS.some(pattern => pattern.test(path)),
+);
 
-export const getShowBreadcumb = (state: State) => state.app.breadcrumbs.show;
+export const getCollectionId = createSelector(
+  [getQuestion, getDashboard],
+  (question, dashboard) =>
+    question ? question.collectionId() : dashboard?.collection_id,
+);
-- 
GitLab