From 426da4a3dc5afc27ff7607423aae4a54b03097c2 Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Mon, 20 Jun 2022 21:32:01 +0300
Subject: [PATCH] Update collection empty state (#23406)

---
 frontend/src/metabase-lib/lib/Question.ts     |   2 +
 frontend/src/metabase-types/api/database.ts   |   4 +
 .../src/metabase-types/api/mocks/database.ts  |   2 +
 .../CollectionEmptyState.styled.tsx           |  35 +++
 .../CollectionEmptyState.tsx                  |  45 +++
 .../components/CollectionEmptyState/index.ts  |   1 +
 .../CollectionHeader/CollectionHeader.jsx     |  13 +-
 .../CollectionHeader.unit.spec.js             |  38 ++-
 .../CollectionLanding/CollectionLanding.tsx   |  29 ++
 .../components/CollectionLanding/index.ts     |   1 +
 .../collections/components/Layout.jsx         |   5 -
 .../components/NewCollectionItemMenu.jsx      |  43 ---
 .../containers/CollectionContent.jsx          |   2 +-
 .../containers/CollectionContent.styled.tsx   |   5 +-
 .../components/CollectionEmptyState.jsx       | 273 ------------------
 .../CollectionLanding/CollectionLanding.jsx   |  27 --
 .../CollectionLanding.styled.jsx              |  11 -
 .../components/NewItemMenu/NewItemMenu.tsx    | 138 +++++++++
 .../metabase/components/NewItemMenu/index.ts  |   1 +
 .../containers/NewItemMenu/NewItemMenu.tsx    |  46 +++
 .../metabase/containers/NewItemMenu/index.ts  |   1 +
 .../NewItemButton/NewItemButton.styled.tsx}   |  16 +-
 .../NewItemButton/NewItemButton.tsx           |  23 ++
 .../nav/components/NewItemButton/index.ts     |   1 +
 .../src/metabase/nav/containers/AppBar.tsx    |   4 +-
 .../nav/containers/NewButton/NewButton.tsx    | 162 -----------
 .../nav/containers/NewButton/index.ts         |   1 -
 frontend/src/metabase/nav/selectors.ts        |  25 ++
 frontend/src/metabase/routes.jsx              |   2 +-
 29 files changed, 400 insertions(+), 556 deletions(-)
 create mode 100644 frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.styled.tsx
 create mode 100644 frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.tsx
 create mode 100644 frontend/src/metabase/collections/components/CollectionEmptyState/index.ts
 create mode 100644 frontend/src/metabase/collections/components/CollectionLanding/CollectionLanding.tsx
 create mode 100644 frontend/src/metabase/collections/components/CollectionLanding/index.ts
 delete mode 100644 frontend/src/metabase/collections/components/Layout.jsx
 delete mode 100644 frontend/src/metabase/collections/components/NewCollectionItemMenu.jsx
 delete mode 100644 frontend/src/metabase/components/CollectionEmptyState.jsx
 delete mode 100644 frontend/src/metabase/components/CollectionLanding/CollectionLanding.jsx
 delete mode 100644 frontend/src/metabase/components/CollectionLanding/CollectionLanding.styled.jsx
 create mode 100644 frontend/src/metabase/components/NewItemMenu/NewItemMenu.tsx
 create mode 100644 frontend/src/metabase/components/NewItemMenu/index.ts
 create mode 100644 frontend/src/metabase/containers/NewItemMenu/NewItemMenu.tsx
 create mode 100644 frontend/src/metabase/containers/NewItemMenu/index.ts
 rename frontend/src/metabase/nav/{containers/NewButton/NewButton.styled.tsx => components/NewItemButton/NewItemButton.styled.tsx} (62%)
 create mode 100644 frontend/src/metabase/nav/components/NewItemButton/NewItemButton.tsx
 create mode 100644 frontend/src/metabase/nav/components/NewItemButton/index.ts
 delete mode 100644 frontend/src/metabase/nav/containers/NewButton/NewButton.tsx
 delete mode 100644 frontend/src/metabase/nav/containers/NewButton/index.ts
 create mode 100644 frontend/src/metabase/nav/selectors.ts

diff --git a/frontend/src/metabase-lib/lib/Question.ts b/frontend/src/metabase-lib/lib/Question.ts
index a32d4ff42d0..32de0f573f9 100644
--- a/frontend/src/metabase-lib/lib/Question.ts
+++ b/frontend/src/metabase-lib/lib/Question.ts
@@ -74,12 +74,14 @@ import {
   ALERT_TYPE_TIMESERIES_GOAL,
 } from "metabase-lib/lib/Alert";
 import { utf8_to_b64url } from "metabase/lib/encoding";
+import { CollectionId } from "metabase-types/api";
 
 type QuestionUpdateFn = (q: Question) => Promise<void> | null | undefined;
 
 export type QuestionCreatorOpts = {
   databaseId?: DatabaseId;
   tableId?: TableId;
+  collectionId?: CollectionId;
   metadata?: Metadata;
   parameterValues?: ParameterValues;
   type?: "query" | "native";
diff --git a/frontend/src/metabase-types/api/database.ts b/frontend/src/metabase-types/api/database.ts
index 950dc47a743..0d81213986d 100644
--- a/frontend/src/metabase-types/api/database.ts
+++ b/frontend/src/metabase-types/api/database.ts
@@ -1,3 +1,5 @@
+import { NativePermissions } from "./permissions";
+
 export type DatabaseId = number;
 
 export type InitialSyncStatus = "incomplete" | "complete" | "aborted";
@@ -7,8 +9,10 @@ export interface Database {
   name: string;
   engine: string;
   is_sample: boolean;
+  is_saved_questions: boolean;
   creator_id?: number;
   created_at: string;
   timezone?: string;
+  native_permissions: NativePermissions;
   initial_sync_status: InitialSyncStatus;
 }
diff --git a/frontend/src/metabase-types/api/mocks/database.ts b/frontend/src/metabase-types/api/mocks/database.ts
index 118a498a200..2c05c6097e4 100644
--- a/frontend/src/metabase-types/api/mocks/database.ts
+++ b/frontend/src/metabase-types/api/mocks/database.ts
@@ -5,9 +5,11 @@ export const createMockDatabase = (opts?: Partial<Database>): Database => ({
   name: "Database",
   engine: "H2",
   is_sample: false,
+  is_saved_questions: false,
   creator_id: undefined,
   created_at: "2015-01-01T20:10:30.200",
   timezone: "UTC",
+  native_permissions: "write",
   initial_sync_status: "complete",
   ...opts,
 });
diff --git a/frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.styled.tsx b/frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.styled.tsx
new file mode 100644
index 00000000000..6e171634ea5
--- /dev/null
+++ b/frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.styled.tsx
@@ -0,0 +1,35 @@
+import styled from "@emotion/styled";
+import { color } from "metabase/lib/colors";
+
+export const EmptyStateRoot = styled.div`
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+`;
+
+export const EmptyStateTitle = styled.div`
+  color: ${color("text-dark")};
+  font-size: 1.5rem;
+  font-weight: bold;
+  line-height: 2rem;
+  margin-top: 2.5rem;
+  margin-bottom: 0.75rem;
+`;
+
+export const EmptyStateDescription = styled.div`
+  color: ${color("text-medium")};
+  font-size: 1rem;
+  line-height: 1.5rem;
+  margin-bottom: 1.5rem;
+  text-align: center;
+`;
+
+export const EmptyStateIconForeground = styled.path`
+  fill: ${color("bg-light")};
+  stroke: ${color("brand")};
+`;
+
+export const EmptyStateIconBackground = styled.path`
+  fill: ${color("brand-light")};
+  stroke: ${color("brand")};
+`;
diff --git a/frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.tsx b/frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.tsx
new file mode 100644
index 00000000000..22f45376e4a
--- /dev/null
+++ b/frontend/src/metabase/collections/components/CollectionEmptyState/CollectionEmptyState.tsx
@@ -0,0 +1,45 @@
+import React from "react";
+import { t } from "ttag";
+import Button from "metabase/core/components/Button";
+import NewItemMenu from "metabase/containers/NewItemMenu";
+import { ANALYTICS_CONTEXT } from "metabase/collections/constants";
+import {
+  EmptyStateDescription,
+  EmptyStateIconBackground,
+  EmptyStateIconForeground,
+  EmptyStateRoot,
+  EmptyStateTitle,
+} from "./CollectionEmptyState.styled";
+
+const CollectionEmptyState = (): JSX.Element => {
+  return (
+    <EmptyStateRoot data-testid="collection-empty-state">
+      <CollectionEmptyIcon />
+      <EmptyStateTitle>{t`This collection is empty`}</EmptyStateTitle>
+      <EmptyStateDescription>{t`Use collections to organize and group dashboards and questions for your team or yourself`}</EmptyStateDescription>
+      <NewItemMenu
+        trigger={<Button icon="add">{t`Create a new…`}</Button>}
+        analyticsContext={ANALYTICS_CONTEXT}
+      />
+    </EmptyStateRoot>
+  );
+};
+
+const CollectionEmptyIcon = (): JSX.Element => {
+  return (
+    <svg width="117" height="94" fill="none" xmlns="http://www.w3.org/2000/svg">
+      <EmptyStateIconForeground
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M12.5 1C6.148 1 .995 6.151 1 12.505l.023 69C1.029 87.854 6.175 93 12.523 93H104.5C110.853 93 116 87.851 116 81.5V22.196c0-6.352-5.147-11.5-11.501-11.5H65.357a5.752 5.752 0 0 1-5.307-3.533l-1.099-2.63A5.752 5.752 0 0 0 53.644 1H12.5Z"
+        strokeWidth="2"
+      />
+      <EmptyStateIconBackground
+        d="M1 13C1 6.373 6.373 1 13 1h39.76a8 8 0 0 1 7.017 4.157l.446.815a8 8 0 0 0 7.017 4.158H107a9 9 0 0 1 9 9V26l-2.714-3.137a16.003 16.003 0 0 0-12.099-5.53H15.383a16 16 0 0 0-13.155 6.893L1 26V13Z"
+        strokeWidth="2"
+      />
+    </svg>
+  );
+};
+
+export default CollectionEmptyState;
diff --git a/frontend/src/metabase/collections/components/CollectionEmptyState/index.ts b/frontend/src/metabase/collections/components/CollectionEmptyState/index.ts
new file mode 100644
index 00000000000..ef732eeef5f
--- /dev/null
+++ b/frontend/src/metabase/collections/components/CollectionEmptyState/index.ts
@@ -0,0 +1 @@
+export { default } from "./CollectionEmptyState";
diff --git a/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.jsx b/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.jsx
index 1fc1b53324a..10710fe8c4c 100644
--- a/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.jsx
+++ b/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.jsx
@@ -10,10 +10,11 @@ import PageHeading from "metabase/components/type/PageHeading";
 import Tooltip from "metabase/components/Tooltip";
 
 import CollectionEditMenu from "metabase/collections/components/CollectionEditMenu";
-import NewCollectionItemMenu from "metabase/collections/components/NewCollectionItemMenu";
+import NewItemMenu from "metabase/containers/NewItemMenu";
 import { color } from "metabase/lib/colors";
 
 import { PLUGIN_COLLECTION_COMPONENTS } from "metabase/plugins";
+import { ANALYTICS_CONTEXT } from "metabase/collections/constants";
 
 import {
   BookmarkIcon,
@@ -140,7 +141,15 @@ function Menu(props) {
 
   return (
     <MenuContainer data-testid="collection-menu">
-      {hasWritePermission && <NewCollectionItemMenu {...props} />}
+      {hasWritePermission && (
+        <NewItemMenu
+          {...props}
+          collectionId={collectionId}
+          triggerIcon="add"
+          triggerTooltip={t`New…`}
+          analyticsContext={ANALYTICS_CONTEXT}
+        />
+      )}
       <EditMenu {...props} />
       <PermissionsLink {...props} />
       <TimelinesLink {...props} />
diff --git a/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.unit.spec.js b/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.unit.spec.js
index 792a0266b24..80ea2e0da46 100644
--- a/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.unit.spec.js
+++ b/frontend/src/metabase/collections/components/CollectionHeader/CollectionHeader.unit.spec.js
@@ -1,6 +1,6 @@
 import React from "react";
-import { render, screen } from "@testing-library/react";
-
+import { screen } from "@testing-library/react";
+import { renderWithProviders } from "__support__/ui";
 import Header from "./CollectionHeader";
 
 const collection = {
@@ -8,7 +8,7 @@ const collection = {
 };
 
 it("should display collection name", () => {
-  render(<Header collection={collection} />);
+  renderWithProviders(<Header collection={collection} />);
 
   screen.getByText(collection.name);
 });
@@ -16,7 +16,9 @@ it("should display collection name", () => {
 describe("description tooltip", () => {
   describe("should not be displayed", () => {
     it("if description is not received", () => {
-      const { container } = render(<Header collection={collection} />);
+      const { container } = renderWithProviders(
+        <Header collection={collection} />,
+      );
       expect(container.textContent).toEqual("Name");
     });
   });
@@ -25,7 +27,9 @@ describe("description tooltip", () => {
     it("if description is received", () => {
       const description = "description";
 
-      render(<Header collection={{ ...collection, description }} />);
+      renderWithProviders(
+        <Header collection={{ ...collection, description }} />,
+      );
 
       screen.getByText(description);
     });
@@ -37,13 +41,13 @@ describe("permissions link", () => {
 
   describe("should not be displayed", () => {
     it("if user is not admin", () => {
-      render(<Header collection={collection} />);
+      renderWithProviders(<Header collection={collection} />);
 
       expect(screen.queryByLabelText(ariaLabel)).not.toBeInTheDocument();
     });
 
     it("for personal collections", () => {
-      render(
+      renderWithProviders(
         <Header
           isAdmin={true}
           collection={{ ...collection, personal_owner_id: 1 }}
@@ -54,7 +58,7 @@ describe("permissions link", () => {
     });
 
     it("if a collection is a personal collection child", () => {
-      render(
+      renderWithProviders(
         <Header
           isAdmin={true}
           collection={collection}
@@ -68,7 +72,7 @@ describe("permissions link", () => {
 
   describe("should be displayed", () => {
     it("if user is admin", () => {
-      render(<Header collection={collection} isAdmin={true} />);
+      renderWithProviders(<Header collection={collection} isAdmin={true} />);
 
       screen.getByLabelText(ariaLabel);
     });
@@ -80,13 +84,15 @@ describe("link to add new collection items", () => {
 
   describe("should not be displayed", () => {
     it("when no detail is passed in the collection to determine if user can change collection", () => {
-      render(<Header collection={collection} />);
+      renderWithProviders(<Header collection={collection} />);
 
       expect(screen.queryByLabelText(ariaLabel)).not.toBeInTheDocument();
     });
 
     it("if user is not allowed to change collection", () => {
-      render(<Header collection={{ ...collection, can_write: false }} />);
+      renderWithProviders(
+        <Header collection={{ ...collection, can_write: false }} />,
+      );
 
       expect(screen.queryByLabelText(ariaLabel)).not.toBeInTheDocument();
     });
@@ -94,7 +100,9 @@ describe("link to add new collection items", () => {
 
   describe("should be displayed", () => {
     it("if user is allowed to change collection", () => {
-      render(<Header collection={{ ...collection, can_write: true }} />);
+      renderWithProviders(
+        <Header collection={{ ...collection, can_write: true }} />,
+      );
 
       screen.getByLabelText(ariaLabel);
     });
@@ -106,7 +114,7 @@ describe("link to add new collection items", () => {
 
   describe("should not be displayed", () => {
     it("if user is not allowed to change collection", () => {
-      render(<Header collection={collection} />);
+      renderWithProviders(<Header collection={collection} />);
 
       expect(screen.queryByLabelText(ariaLabel)).not.toBeInTheDocument();
     });
@@ -114,7 +122,9 @@ describe("link to add new collection items", () => {
 
   describe("should be displayed", () => {
     it("if user is allowed to change collection", () => {
-      render(<Header collection={{ ...collection, can_write: true }} />);
+      renderWithProviders(
+        <Header collection={{ ...collection, can_write: true }} />,
+      );
 
       screen.getByLabelText(ariaLabel);
     });
diff --git a/frontend/src/metabase/collections/components/CollectionLanding/CollectionLanding.tsx b/frontend/src/metabase/collections/components/CollectionLanding/CollectionLanding.tsx
new file mode 100644
index 00000000000..fcf3dc82abe
--- /dev/null
+++ b/frontend/src/metabase/collections/components/CollectionLanding/CollectionLanding.tsx
@@ -0,0 +1,29 @@
+import React, { ReactNode } from "react";
+import { extractCollectionId } from "metabase/lib/urls";
+import CollectionContent from "../../containers/CollectionContent";
+
+export interface CollectionLandingProps {
+  params: CollectionLandingParams;
+  children?: ReactNode;
+}
+
+export interface CollectionLandingParams {
+  slug: string;
+}
+
+const CollectionLanding = ({
+  params: { slug },
+  children,
+}: CollectionLandingProps) => {
+  const collectionId = extractCollectionId(slug);
+  const isRoot = collectionId === "root";
+
+  return (
+    <>
+      <CollectionContent isRoot={isRoot} collectionId={collectionId} />
+      {children}
+    </>
+  );
+};
+
+export default CollectionLanding;
diff --git a/frontend/src/metabase/collections/components/CollectionLanding/index.ts b/frontend/src/metabase/collections/components/CollectionLanding/index.ts
new file mode 100644
index 00000000000..bd66ac36b61
--- /dev/null
+++ b/frontend/src/metabase/collections/components/CollectionLanding/index.ts
@@ -0,0 +1 @@
+export { default } from "./CollectionLanding";
diff --git a/frontend/src/metabase/collections/components/Layout.jsx b/frontend/src/metabase/collections/components/Layout.jsx
deleted file mode 100644
index 816a1b2b0b2..00000000000
--- a/frontend/src/metabase/collections/components/Layout.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import styled from "@emotion/styled";
-
-export const PageWrapper = styled.div`
-  overflow: hidden;
-`;
diff --git a/frontend/src/metabase/collections/components/NewCollectionItemMenu.jsx b/frontend/src/metabase/collections/components/NewCollectionItemMenu.jsx
deleted file mode 100644
index 4e4af5cb587..00000000000
--- a/frontend/src/metabase/collections/components/NewCollectionItemMenu.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from "react";
-import PropTypes from "prop-types";
-import { t } from "ttag";
-
-import { newQuestion, newDashboard, newCollection } from "metabase/lib/urls";
-
-import EntityMenu from "metabase/components/EntityMenu";
-import { ANALYTICS_CONTEXT } from "metabase/collections/constants";
-
-const propTypes = {
-  collection: PropTypes.object,
-  list: PropTypes.arrayOf(PropTypes.object),
-  canCreateQuestions: PropTypes.bool,
-};
-
-function NewCollectionItemMenu({ collection, canCreateQuestions }) {
-  const items = [
-    canCreateQuestions && {
-      icon: "insight",
-      title: t`Question`,
-      link: newQuestion({ mode: "notebook", collectionId: collection.id }),
-      event: `${ANALYTICS_CONTEXT};New Item Menu;Question Click`,
-    },
-    {
-      icon: "dashboard",
-      title: t`Dashboard`,
-      link: newDashboard(collection.id),
-      event: `${ANALYTICS_CONTEXT};New Item Menu;Dashboard Click`,
-    },
-    {
-      icon: "folder",
-      title: t`Collection`,
-      link: newCollection(collection.id),
-      event: `${ANALYTICS_CONTEXT};New Item Menu;Collection Click`,
-    },
-  ].filter(Boolean);
-
-  return <EntityMenu items={items} triggerIcon="add" tooltip={t`New…`} />;
-}
-
-NewCollectionItemMenu.propTypes = propTypes;
-
-export default NewCollectionItemMenu;
diff --git a/frontend/src/metabase/collections/containers/CollectionContent.jsx b/frontend/src/metabase/collections/containers/CollectionContent.jsx
index 8a52ea0825b..e8bdef14651 100644
--- a/frontend/src/metabase/collections/containers/CollectionContent.jsx
+++ b/frontend/src/metabase/collections/containers/CollectionContent.jsx
@@ -13,7 +13,7 @@ import { getIsBookmarked } from "metabase/collections/selectors";
 import { getIsNavbarOpen, openNavbar } from "metabase/redux/app";
 
 import BulkActions from "metabase/collections/components/BulkActions";
-import CollectionEmptyState from "metabase/components/CollectionEmptyState";
+import CollectionEmptyState from "metabase/collections/components/CollectionEmptyState";
 import Header from "metabase/collections/containers/CollectionHeader";
 import ItemsTable from "metabase/collections/components/ItemsTable";
 import PinnedItemOverview from "metabase/collections/components/PinnedItemOverview";
diff --git a/frontend/src/metabase/collections/containers/CollectionContent.styled.tsx b/frontend/src/metabase/collections/containers/CollectionContent.styled.tsx
index 2800f76ce9a..b68f5a3512f 100644
--- a/frontend/src/metabase/collections/containers/CollectionContent.styled.tsx
+++ b/frontend/src/metabase/collections/containers/CollectionContent.styled.tsx
@@ -18,8 +18,5 @@ export const CollectionTable = styled.div<CollectionTableProps>`
 `;
 
 export const CollectionEmptyContent = styled.div`
-  display: flex;
-  justify-content: center;
-  align-items: start;
-  margin-top: 3rem;
+  margin-top: calc(20vh - 3.5rem);
 `;
diff --git a/frontend/src/metabase/components/CollectionEmptyState.jsx b/frontend/src/metabase/components/CollectionEmptyState.jsx
deleted file mode 100644
index 1bba88a3367..00000000000
--- a/frontend/src/metabase/components/CollectionEmptyState.jsx
+++ /dev/null
@@ -1,273 +0,0 @@
-import React from "react";
-
-function CollectionEmptyState() {
-  return (
-    <svg
-      style={{ maxWidth: 1120 }}
-      data-testid="collection-empty-state"
-      viewBox="0 0 944 672"
-      fill="none"
-      xmlns="http://www.w3.org/2000/svg"
-    >
-      <rect
-        opacity="0.7"
-        x="0.5"
-        y="0.5"
-        width="463"
-        height="215"
-        rx="7.5"
-        fill="white"
-        stroke="#F0F0F0"
-      />
-      <rect
-        width="42"
-        height="200"
-        transform="matrix(-1 0 0 1 428 16)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        width="42"
-        height="177"
-        transform="matrix(-1 0 0 1 378 39)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        width="42"
-        height="127.941"
-        transform="matrix(-1 0 0 1 328 88.0588)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        width="42"
-        height="83.8235"
-        transform="matrix(-1 0 0 1 278 132.176)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        width="42"
-        height="41.1765"
-        transform="matrix(-1 0 0 1 228 174.824)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        width="42"
-        height="147.059"
-        transform="matrix(-1 0 0 1 178 68.9412)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        width="42"
-        height="110"
-        transform="matrix(-1 0 0 1 128 106)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        width="42"
-        height="84"
-        transform="matrix(-1 0 0 1 78 132)"
-        fill="#EDF2F5"
-        fillOpacity="0.5"
-      />
-      <rect
-        opacity="0.7"
-        x="483.049"
-        y="0.5"
-        width="460.451"
-        height="215"
-        rx="7.5"
-        fill="white"
-        stroke="#F0F0F0"
-      />
-      <path
-        opacity="0.5"
-        d="M550.992 198.14L515.496 184.744L480 192.48V208C480 212.418 483.582 216 488 216H933.451C937.869 216 941.451 212.418 941.451 208V24L905.954 35.1628L870.458 59.7209L834.962 44.093L799.466 77.5814L763.97 59.7209L728.473 86.5116L692.977 104.372L657.481 77.5814L621.985 176.93L586.489 150.14L550.992 198.14Z"
-        fill="#EDF2F5"
-      />
-      <path
-        d="M481.275 193.44L515.496 184.744L550.992 198.14L586.488 150.14L621.985 176.93L657.481 77.5814L692.977 104.372L728.473 86.5116L763.969 59.7209L799.466 77.5814L834.962 44.093L870.458 59.7209L905.954 35.1628L941.45 24"
-        stroke="#EDF2F5"
-        strokeWidth="2"
-      />
-      <rect
-        opacity="0.7"
-        x="0.5"
-        y="232.5"
-        width="463"
-        height="127"
-        rx="7.5"
-        fill="white"
-        stroke="#F0F0F0"
-      />
-      <path
-        fillRule="evenodd"
-        clipRule="evenodd"
-        d="M216 281.714C216 279.505 217.791 277.714 220 277.714H244H245C246.657 277.714 248 279.057 248 280.714V281.714V285.714V305.714C248 307.923 246.209 309.714 244 309.714H220C218.136 309.714 216.57 308.44 216.126 306.714H216V305.714V285.714V281.714ZM244 285.714V305.714H220V285.714H244ZM233.455 296.623H223.273V300.987H233.455V296.623ZM223.273 289.805H240.727V294.169H223.273V289.805ZM240.727 296.623H236.364V300.987H240.727V296.623Z"
-        fill="#EDF2F5"
-      />
-      <rect
-        opacity="0.7"
-        x="480.5"
-        y="232.5"
-        width="463"
-        height="127"
-        rx="7.5"
-        fill="white"
-        stroke="#F0F0F0"
-      />
-      <path
-        fillRule="evenodd"
-        clipRule="evenodd"
-        d="M696 281.714C696 279.505 697.791 277.714 700 277.714H724H725C726.657 277.714 728 279.057 728 280.714V281.714V285.714V305.714C728 307.923 726.209 309.714 724 309.714H700C698.136 309.714 696.57 308.44 696.126 306.714H696V305.714V285.714V281.714ZM724 285.714V305.714H700V285.714H724ZM713.455 296.623H703.273V300.987H713.455V296.623ZM703.273 289.805H720.727V294.169H703.273V289.805ZM720.727 296.623H716.364V300.987H720.727V296.623Z"
-        fill="#EDF2F5"
-      />
-      <rect y="440" width="258.683" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="440"
-        width="113.898"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="440"
-        width="103.28"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="472" width="402.503" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="472"
-        width="99.4192"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="472"
-        width="113.898"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="504" width="207.526" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="504"
-        width="130.307"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="504"
-        width="89.7669"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="536" width="354.241" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="536"
-        width="113.898"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="536"
-        width="103.28"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="568" width="370.65" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="568"
-        width="106.176"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="568"
-        width="89.7669"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="600" width="233.587" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="600"
-        width="138.029"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="600"
-        width="103.28"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="632" width="284.744" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="632"
-        width="106.176"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="632"
-        width="103.28"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="664" width="258.683" height="8" rx="4" fill="#EDF2F5" />
-      <rect
-        x="630.708"
-        y="664"
-        width="113.898"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect
-        x="830.102"
-        y="664"
-        width="113.898"
-        height="8"
-        rx="4"
-        fill="#EDF2F5"
-      />
-      <rect y="408" width="50.1239" height="8" rx="4" fill="#EDF2F5" />
-      <rect x="631" y="408" width="73.515" height="8" rx="4" fill="#EDF2F5" />
-      <rect x="830" y="408" width="60.9841" height="8" rx="4" fill="#EDF2F5" />
-    </svg>
-  );
-}
-
-export default CollectionEmptyState;
diff --git a/frontend/src/metabase/components/CollectionLanding/CollectionLanding.jsx b/frontend/src/metabase/components/CollectionLanding/CollectionLanding.jsx
deleted file mode 100644
index 621747ec416..00000000000
--- a/frontend/src/metabase/components/CollectionLanding/CollectionLanding.jsx
+++ /dev/null
@@ -1,27 +0,0 @@
-/* eslint-disable react/prop-types */
-import React from "react";
-
-import { extractCollectionId } from "metabase/lib/urls";
-
-import { PageWrapper } from "metabase/collections/components/Layout";
-import CollectionContent from "metabase/collections/containers/CollectionContent";
-import { ContentBox } from "./CollectionLanding.styled";
-
-const CollectionLanding = ({ params: { slug }, children }) => {
-  const collectionId = extractCollectionId(slug);
-  const isRoot = collectionId === "root";
-
-  return (
-    <PageWrapper>
-      <ContentBox>
-        <CollectionContent isRoot={isRoot} collectionId={collectionId} />
-      </ContentBox>
-      {
-        // Need to have this here so the child modals will show up
-        children
-      }
-    </PageWrapper>
-  );
-};
-
-export default CollectionLanding;
diff --git a/frontend/src/metabase/components/CollectionLanding/CollectionLanding.styled.jsx b/frontend/src/metabase/components/CollectionLanding/CollectionLanding.styled.jsx
deleted file mode 100644
index d2f2c7e837f..00000000000
--- a/frontend/src/metabase/components/CollectionLanding/CollectionLanding.styled.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import styled from "@emotion/styled";
-
-import { breakpointMinSmall } from "metabase/styled-components/theme/media-queries";
-
-export const ContentBox = styled.div`
-  overflow-y: auto;
-
-  ${breakpointMinSmall} {
-    display: block;
-  }
-`;
diff --git a/frontend/src/metabase/components/NewItemMenu/NewItemMenu.tsx b/frontend/src/metabase/components/NewItemMenu/NewItemMenu.tsx
new file mode 100644
index 00000000000..dd1efe2d1b1
--- /dev/null
+++ b/frontend/src/metabase/components/NewItemMenu/NewItemMenu.tsx
@@ -0,0 +1,138 @@
+import React, { ReactNode, useCallback, useMemo, useState } from "react";
+import { t } from "ttag";
+import * as Urls from "metabase/lib/urls";
+import Modal from "metabase/components/Modal";
+import EntityMenu from "metabase/components/EntityMenu";
+import CreateDashboardModal from "metabase/components/CreateDashboardModal";
+import CollectionCreate from "metabase/collections/containers/CollectionCreate";
+import { Collection, CollectionId } from "metabase-types/api";
+
+type ModalType = "new-dashboard" | "new-collection";
+
+export interface NewItemMenuProps {
+  className?: string;
+  collectionId?: CollectionId;
+  trigger?: ReactNode;
+  triggerIcon?: string;
+  triggerTooltip?: string;
+  analyticsContext?: string;
+  hasDataAccess: boolean;
+  hasNativeWrite: boolean;
+  hasDatabaseWithJsonEngine: boolean;
+  onChangeLocation: (location: string) => void;
+  onCloseNavbar: () => void;
+}
+
+const NewItemMenu = ({
+  className,
+  collectionId,
+  trigger,
+  triggerIcon,
+  triggerTooltip,
+  analyticsContext,
+  hasDataAccess,
+  hasNativeWrite,
+  hasDatabaseWithJsonEngine,
+  onChangeLocation,
+  onCloseNavbar,
+}: NewItemMenuProps) => {
+  const [modal, setModal] = useState<ModalType>();
+
+  const handleModalClose = useCallback(() => {
+    setModal(undefined);
+  }, []);
+
+  const handleCollectionSave = useCallback(
+    (collection: Collection) => {
+      handleModalClose();
+      onChangeLocation(Urls.collection(collection));
+    },
+    [handleModalClose, onChangeLocation],
+  );
+
+  const menuItems = useMemo(() => {
+    const items = [];
+
+    if (hasDataAccess) {
+      items.push({
+        title: t`Question`,
+        icon: "insight",
+        link: Urls.newQuestion({
+          mode: "notebook",
+          creationType: "custom_question",
+          collectionId,
+        }),
+        event: `${analyticsContext};New Question Click;`,
+        onClose: onCloseNavbar,
+      });
+    }
+
+    if (hasNativeWrite) {
+      items.push({
+        title: hasDatabaseWithJsonEngine ? t`Native query` : t`SQL query`,
+        icon: "sql",
+        link: Urls.newQuestion({
+          type: "native",
+          creationType: "native_question",
+          collectionId,
+        }),
+        event: `${analyticsContext};New SQL Query Click;`,
+        onClose: onCloseNavbar,
+      });
+    }
+
+    items.push(
+      {
+        title: t`Dashboard`,
+        icon: "dashboard",
+        action: () => setModal("new-dashboard"),
+        event: `${analyticsContext};New Dashboard Click;`,
+      },
+      {
+        title: t`Collection`,
+        icon: "folder",
+        action: () => setModal("new-collection"),
+        event: `${analyticsContext};New Collection Click;`,
+      },
+    );
+
+    return items;
+  }, [
+    collectionId,
+    hasDataAccess,
+    hasNativeWrite,
+    hasDatabaseWithJsonEngine,
+    analyticsContext,
+    onCloseNavbar,
+  ]);
+
+  return (
+    <>
+      <EntityMenu
+        className={className}
+        items={menuItems}
+        trigger={trigger}
+        triggerIcon={triggerIcon}
+        tooltip={triggerTooltip}
+      />
+      {modal && (
+        <Modal onClose={handleModalClose}>
+          {modal === "new-collection" ? (
+            <CollectionCreate
+              collectionId={collectionId}
+              onClose={handleModalClose}
+              onSaved={handleCollectionSave}
+            />
+          ) : modal === "new-dashboard" ? (
+            <CreateDashboardModal
+              collectionId={collectionId}
+              onClose={handleModalClose}
+            />
+          ) : null}
+        </Modal>
+      )}
+    </>
+  );
+};
+
+export default NewItemMenu;
diff --git a/frontend/src/metabase/components/NewItemMenu/index.ts b/frontend/src/metabase/components/NewItemMenu/index.ts
new file mode 100644
index 00000000000..734e3d64075
--- /dev/null
+++ b/frontend/src/metabase/components/NewItemMenu/index.ts
@@ -0,0 +1 @@
+export { default } from "./NewItemMenu";
diff --git a/frontend/src/metabase/containers/NewItemMenu/NewItemMenu.tsx b/frontend/src/metabase/containers/NewItemMenu/NewItemMenu.tsx
new file mode 100644
index 00000000000..62cabbcf75c
--- /dev/null
+++ b/frontend/src/metabase/containers/NewItemMenu/NewItemMenu.tsx
@@ -0,0 +1,46 @@
+import { ReactNode } from "react";
+import { connect } from "react-redux";
+import { push } from "react-router-redux";
+import { closeNavbar } from "metabase/redux/app";
+import NewItemMenu from "metabase/components/NewItemMenu";
+import {
+  getHasDataAccess,
+  getHasDatabaseWithJsonEngine,
+  getHasNativeWrite,
+} from "metabase/nav/selectors";
+import { State } from "metabase-types/store";
+
+interface MenuOwnProps {
+  className?: string;
+  trigger?: ReactNode;
+  triggerIcon?: string;
+  triggerTooltip?: string;
+  analyticsContext?: string;
+}
+
+interface MenuStateProps {
+  hasDataAccess: boolean;
+  hasNativeWrite: boolean;
+  hasDatabaseWithJsonEngine: boolean;
+}
+
+interface MenuDispatchProps {
+  onChangeLocation: (location: string) => void;
+  onCloseNavbar: () => void;
+}
+
+const mapStateToProps = (state: State): MenuStateProps => ({
+  hasDataAccess: getHasDataAccess(state),
+  hasNativeWrite: getHasNativeWrite(state),
+  hasDatabaseWithJsonEngine: getHasDatabaseWithJsonEngine(state),
+});
+
+const mapDispatchToProps = {
+  onChangeLocation: push,
+  onCloseNavbar: closeNavbar,
+};
+
+export default connect<MenuStateProps, MenuDispatchProps, MenuOwnProps, State>(
+  mapStateToProps,
+  mapDispatchToProps,
+)(NewItemMenu);
diff --git a/frontend/src/metabase/containers/NewItemMenu/index.ts b/frontend/src/metabase/containers/NewItemMenu/index.ts
new file mode 100644
index 00000000000..734e3d64075
--- /dev/null
+++ b/frontend/src/metabase/containers/NewItemMenu/index.ts
@@ -0,0 +1 @@
+export { default } from "./NewItemMenu";
diff --git a/frontend/src/metabase/nav/containers/NewButton/NewButton.styled.tsx b/frontend/src/metabase/nav/components/NewItemButton/NewItemButton.styled.tsx
similarity index 62%
rename from frontend/src/metabase/nav/containers/NewButton/NewButton.styled.tsx
rename to frontend/src/metabase/nav/components/NewItemButton/NewItemButton.styled.tsx
index ac9d0c58953..d83e2d8efbd 100644
--- a/frontend/src/metabase/nav/containers/NewButton/NewButton.styled.tsx
+++ b/frontend/src/metabase/nav/components/NewItemButton/NewItemButton.styled.tsx
@@ -1,11 +1,9 @@
 import styled from "@emotion/styled";
-
-import EntityMenu from "metabase/components/EntityMenu";
-import Button from "metabase/core/components/Button";
-
+import Button from "metabase/core/components/Button/Button";
+import NewItemMenu from "metabase/containers/NewItemMenu";
 import { breakpointMaxSmall } from "metabase/styled-components/theme";
 
-export const Menu = styled(EntityMenu)`
+export const NewMenu = styled(NewItemMenu)`
   margin-right: 0.5rem;
 
   ${breakpointMaxSmall} {
@@ -13,12 +11,12 @@ export const Menu = styled(EntityMenu)`
   }
 `;
 
-export const StyledButton = styled(Button)`
+export const NewButton = styled(Button)`
   display: flex;
   align-items: center;
+  height: 2.25rem;
   margin-right: 0.5rem;
   padding: 0.5rem;
-  height: 36px;
 
   ${Button.TextContainer} {
     margin-left: 0;
@@ -29,10 +27,8 @@ export const StyledButton = styled(Button)`
   }
 `;
 
-export const Title = styled.h4`
+export const NewButtonText = styled.h4`
   display: inline;
-
   margin-left: 0.5rem;
-
   white-space: nowrap;
 `;
diff --git a/frontend/src/metabase/nav/components/NewItemButton/NewItemButton.tsx b/frontend/src/metabase/nav/components/NewItemButton/NewItemButton.tsx
new file mode 100644
index 00000000000..b9b24342b06
--- /dev/null
+++ b/frontend/src/metabase/nav/components/NewItemButton/NewItemButton.tsx
@@ -0,0 +1,23 @@
+import React from "react";
+import { t } from "ttag";
+import { NewButton, NewButtonText, NewMenu } from "./NewItemButton.styled";
+
+const NewItemButton = () => {
+  return (
+    <NewMenu
+      trigger={
+        <NewButton
+          primary
+          icon="add"
+          iconSize={14}
+          data-metabase-event="NavBar;Create Menu Click"
+        >
+          <NewButtonText>{t`New`}</NewButtonText>
+        </NewButton>
+      }
+      analyticsContext={"NavBar"}
+    />
+  );
+};
+
+export default NewItemButton;
diff --git a/frontend/src/metabase/nav/components/NewItemButton/index.ts b/frontend/src/metabase/nav/components/NewItemButton/index.ts
new file mode 100644
index 00000000000..d4ff42c65c6
--- /dev/null
+++ b/frontend/src/metabase/nav/components/NewItemButton/index.ts
@@ -0,0 +1 @@
+export { default } from "./NewItemButton";
diff --git a/frontend/src/metabase/nav/containers/AppBar.tsx b/frontend/src/metabase/nav/containers/AppBar.tsx
index 4597f673a58..252c3f77097 100644
--- a/frontend/src/metabase/nav/containers/AppBar.tsx
+++ b/frontend/src/metabase/nav/containers/AppBar.tsx
@@ -9,7 +9,7 @@ import LogoIcon from "metabase/components/LogoIcon";
 
 import SearchBar from "metabase/nav/components/SearchBar";
 import SidebarButton from "metabase/nav/components/SidebarButton";
-import NewButton from "metabase/nav/containers/NewButton";
+import NewItemButton from "metabase/nav/components/NewItemButton";
 import PathBreadcrumbs from "../components/PathBreadcrumbs/PathBreadcrumbs";
 
 import { State } from "metabase-types/store";
@@ -150,7 +150,7 @@ function AppBar({
               </SearchBarContent>
             </SearchBarContainer>
           )}
-          {isNewButtonVisible && <NewButton />}
+          {isNewButtonVisible && <NewItemButton />}
         </RightContainer>
       )}
     </AppBarRoot>
diff --git a/frontend/src/metabase/nav/containers/NewButton/NewButton.tsx b/frontend/src/metabase/nav/containers/NewButton/NewButton.tsx
deleted file mode 100644
index 4df5e973e40..00000000000
--- a/frontend/src/metabase/nav/containers/NewButton/NewButton.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-import React, { useCallback, useMemo, useState } from "react";
-import { t } from "ttag";
-import _ from "underscore";
-import { connect } from "react-redux";
-import { push } from "react-router-redux";
-import { LocationDescriptor } from "history";
-
-import Modal from "metabase/components/Modal";
-import CreateDashboardModal from "metabase/components/CreateDashboardModal";
-
-import { Collection } from "metabase-types/api";
-import { State } from "metabase-types/store";
-
-import CollectionCreate from "metabase/collections/containers/CollectionCreate";
-
-import { closeNavbar } from "metabase/redux/app";
-import * as Urls from "metabase/lib/urls";
-import {
-  getHasDataAccess,
-  getHasNativeWrite,
-  getHasDbWithJsonEngine,
-} from "metabase/new_query/selectors";
-
-import { Menu, StyledButton, Title } from "./NewButton.styled";
-
-type NewButtonModal = "MODAL_NEW_DASHBOARD" | "MODAL_NEW_COLLECTION" | null;
-
-const MODAL_NEW_DASHBOARD: NewButtonModal = "MODAL_NEW_DASHBOARD";
-const MODAL_NEW_COLLECTION: NewButtonModal = "MODAL_NEW_COLLECTION";
-
-interface NewButtonStateProps {
-  hasDataAccess: boolean;
-  hasNativeWrite: boolean;
-  hasDbWithJsonEngine: boolean;
-}
-
-interface NewButtonDispatchProps {
-  onChangeLocation: (nextLocation: LocationDescriptor) => void;
-  closeNavbar: () => void;
-}
-
-interface NewButtonProps extends NewButtonStateProps, NewButtonDispatchProps {}
-
-const mapStateToProps: (state: State) => NewButtonStateProps = state => ({
-  hasDataAccess: getHasDataAccess(state),
-  hasNativeWrite: getHasNativeWrite(state),
-  hasDbWithJsonEngine: getHasDbWithJsonEngine(state),
-});
-
-const mapDispatchToProps = {
-  onChangeLocation: push,
-  closeNavbar,
-};
-
-function NewButton({
-  hasDataAccess,
-  hasNativeWrite,
-  hasDbWithJsonEngine,
-  onChangeLocation,
-  closeNavbar,
-}: NewButtonProps) {
-  const [modal, setModal] = useState<NewButtonModal>(null);
-
-  const closeModal = useCallback(() => setModal(null), []);
-
-  const renderModalContent = useCallback(() => {
-    if (modal === MODAL_NEW_COLLECTION) {
-      return (
-        <CollectionCreate
-          onClose={closeModal}
-          onSaved={(collection: Collection) => {
-            closeModal();
-            onChangeLocation(Urls.collection(collection));
-          }}
-        />
-      );
-    }
-    if (modal === MODAL_NEW_DASHBOARD) {
-      return <CreateDashboardModal onClose={closeModal} />;
-    }
-    return null;
-  }, [modal, closeModal, onChangeLocation]);
-
-  const menuItems = useMemo(() => {
-    const items = [];
-
-    if (hasDataAccess) {
-      items.push({
-        title: t`Question`,
-        icon: "insight",
-        link: Urls.newQuestion({
-          mode: "notebook",
-          creationType: "custom_question",
-        }),
-        event: "NavBar;New Question Click;",
-        onClose: closeNavbar,
-      });
-    }
-
-    if (hasNativeWrite) {
-      items.push({
-        title: hasDbWithJsonEngine ? t`Native query` : t`SQL query`,
-        icon: "sql",
-        link: Urls.newQuestion({
-          type: "native",
-          creationType: "native_question",
-        }),
-        event: "NavBar;New SQL Query Click;",
-        onClose: closeNavbar,
-      });
-    }
-
-    items.push(
-      {
-        title: t`Dashboard`,
-        icon: "dashboard",
-        action: () => setModal(MODAL_NEW_DASHBOARD),
-        event: "NavBar;New Dashboard Click;",
-      },
-      {
-        title: t`Collection`,
-        icon: "folder",
-        action: () => setModal(MODAL_NEW_COLLECTION),
-        event: "NavBar;New Collection Click;",
-      },
-    );
-
-    return items;
-  }, [
-    hasDataAccess,
-    hasNativeWrite,
-    hasDbWithJsonEngine,
-    closeNavbar,
-    setModal,
-  ]);
-
-  return (
-    <>
-      <Menu
-        trigger={
-          <StyledButton
-            primary
-            icon="add"
-            iconSize={14}
-            data-metabase-event="NavBar;Create Menu Click"
-          >
-            <Title>{t`New`}</Title>
-          </StyledButton>
-        }
-        items={menuItems}
-      />
-      {modal && <Modal onClose={closeModal}>{renderModalContent()}</Modal>}
-    </>
-  );
-}
-
-export default _.compose(
-  connect<NewButtonStateProps, NewButtonDispatchProps, unknown, State>(
-    mapStateToProps,
-    mapDispatchToProps,
-  ),
-)(NewButton);
diff --git a/frontend/src/metabase/nav/containers/NewButton/index.ts b/frontend/src/metabase/nav/containers/NewButton/index.ts
deleted file mode 100644
index 8206a487828..00000000000
--- a/frontend/src/metabase/nav/containers/NewButton/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./NewButton";
diff --git a/frontend/src/metabase/nav/selectors.ts b/frontend/src/metabase/nav/selectors.ts
new file mode 100644
index 00000000000..6948ea6cc3e
--- /dev/null
+++ b/frontend/src/metabase/nav/selectors.ts
@@ -0,0 +1,25 @@
+import { createSelector } from "reselect";
+import { getEngineNativeType } from "metabase/lib/engine";
+import { State } from "metabase-types/store";
+
+const getDatabaseList = createSelector(
+  (state: State) => state.entities.databases,
+  databases => (databases ? Object.values(databases) : []),
+);
+
+export const getHasDataAccess = createSelector([getDatabaseList], databases =>
+  databases.some(d => !d.is_saved_questions),
+);
+
+export const getHasOwnDatabase = createSelector([getDatabaseList], databases =>
+  databases.some(d => !d.is_sample && !d.is_saved_questions),
+);
+
+export const getHasNativeWrite = createSelector([getDatabaseList], databases =>
+  databases.some(d => d.native_permissions === "write"),
+);
+
+export const getHasDatabaseWithJsonEngine = createSelector(
+  [getDatabaseList],
+  databases => databases.some(d => getEngineNativeType(d.engine) === "json"),
+);
diff --git a/frontend/src/metabase/routes.jsx b/frontend/src/metabase/routes.jsx
index 212c8f4a9b7..8c69e758bbe 100644
--- a/frontend/src/metabase/routes.jsx
+++ b/frontend/src/metabase/routes.jsx
@@ -84,7 +84,7 @@ import DashboardDetailsModal from "metabase/dashboard/components/DashboardDetail
 import { ModalRoute } from "metabase/hoc/ModalRoute";
 
 import HomePage from "metabase/home/homepage/containers/HomePage";
-import CollectionLanding from "metabase/components/CollectionLanding/CollectionLanding";
+import CollectionLanding from "metabase/collections/components/CollectionLanding";
 
 import ArchiveApp from "metabase/home/containers/ArchiveApp";
 import SearchApp from "metabase/home/containers/SearchApp";
-- 
GitLab