diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/ViewHeader.jsx b/frontend/src/metabase/query_builder/components/view/ViewHeader/ViewHeader.jsx
index 9c41a6054c21ea41bcdced772e521d072db97a8a..4c30abe60f711e82a297ae6bb4d13bd19079e07f 100644
--- a/frontend/src/metabase/query_builder/components/view/ViewHeader/ViewHeader.jsx
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/ViewHeader.jsx
@@ -1,55 +1,18 @@
-import cx from "classnames";
 import PropTypes from "prop-types";
-import { useEffect, useCallback, useState } from "react";
+import { useCallback, useEffect } from "react";
 import { usePrevious } from "react-use";
-import { t } from "ttag";
 
-import Link from "metabase/core/components/Link";
-import Tooltip from "metabase/core/components/Tooltip";
-import CS from "metabase/css/core/index.css";
 import { useToggle } from "metabase/hooks/use-toggle";
-import { SERVER_ERROR_TYPES } from "metabase/lib/errors";
-import { useDispatch, useSelector } from "metabase/lib/redux";
-import MetabaseSettings from "metabase/lib/settings";
-import * as Urls from "metabase/lib/urls";
-import { navigateBackToDashboard } from "metabase/query_builder/actions";
-import SavedQuestionHeaderButton from "metabase/query_builder/components/SavedQuestionHeaderButton/SavedQuestionHeaderButton";
-import { MODAL_TYPES } from "metabase/query_builder/constants";
-import { getDashboard } from "metabase/query_builder/selectors";
 import * as Lib from "metabase-lib";
 
+import { ViewHeaderContainer } from "./ViewHeader.styled";
 import {
-  AdHocViewHeading,
-  SaveButton,
-  SavedQuestionHeaderButtonContainer,
-  ViewHeaderMainLeftContentContainer,
-  ViewHeaderLeftSubHeading,
-  ViewHeaderContainer,
-  StyledLastEditInfoLabel,
-  StyledQuestionDataSource,
-  SavedQuestionLeftSideRoot,
-  AdHocLeftSideRoot,
-  HeaderDivider,
-  ViewHeaderActionPanel,
-  ViewHeaderIconButtonContainer,
-  BackButton,
-  BackButtonContainer,
-  ViewRunButtonWithTooltip,
-} from "./ViewHeader.styled";
-import {
-  ToggleNativeQueryPreview,
-  HeadBreadcrumbs,
-  FilterHeaderButton,
-  FilterHeaderToggle,
+  AdHocQuestionLeftSide,
   FilterHeader,
-  ExploreResultsLink,
-  QuestionActions,
-  QuestionNotebookButton,
-  QuestionDataSource,
-  QuestionDescription,
-  QuestionSummarizeWidget,
+  SavedQuestionLeftSide,
+  ViewTitleHeaderRightSide,
+  DashboardBackButton,
 } from "./components";
-import { canExploreResults } from "./utils";
 
 const viewTitleHeaderPropTypes = {
   question: PropTypes.object.isRequired,
@@ -140,7 +103,7 @@ export function ViewTitleHeader(props) {
         {isSaved ? (
           <SavedQuestionLeftSide {...props} />
         ) : (
-          <AhHocQuestionLeftSide
+          <AdHocQuestionLeftSide
             {...props}
             isNative={isNative}
             isSummarized={isSummarized}
@@ -170,394 +133,4 @@ export function ViewTitleHeader(props) {
   );
 }
 
-function DashboardBackButton() {
-  const dashboard = useSelector(getDashboard);
-  const dispatch = useDispatch();
-
-  const handleClick = () => {
-    dispatch(navigateBackToDashboard(dashboard.id));
-  };
-
-  if (!dashboard) {
-    return null;
-  }
-
-  const label = t`Back to ${dashboard.name}`;
-
-  return (
-    <Tooltip tooltip={label}>
-      <BackButtonContainer>
-        <BackButton
-          as={Link}
-          to={Urls.dashboard(dashboard)}
-          round
-          icon="arrow_left"
-          aria-label={label}
-          onClick={handleClick}
-        />
-      </BackButtonContainer>
-    </Tooltip>
-  );
-}
-
-SavedQuestionLeftSide.propTypes = {
-  question: PropTypes.object.isRequired,
-  isObjectDetail: PropTypes.bool,
-  isAdditionalInfoVisible: PropTypes.bool,
-  isShowingQuestionDetailsSidebar: PropTypes.bool,
-  onOpenQuestionInfo: PropTypes.func.isRequired,
-  onSave: PropTypes.func,
-};
-
-function SavedQuestionLeftSide(props) {
-  const {
-    question,
-    isObjectDetail,
-    isAdditionalInfoVisible,
-    onOpenQuestionInfo,
-    onSave,
-  } = props;
-
-  const [showSubHeader, setShowSubHeader] = useState(true);
-
-  const hasLastEditInfo = question.lastEditInfo() != null;
-  const type = question.type();
-  const isModelOrMetric = type === "model" || type === "metric";
-
-  const onHeaderChange = useCallback(
-    name => {
-      if (name && name !== question.displayName()) {
-        onSave(question.setDisplayName(name));
-      }
-    },
-    [question, onSave],
-  );
-
-  const renderDataSource =
-    QuestionDataSource.shouldRender(props) && type === "question";
-  const renderLastEdit = hasLastEditInfo && isAdditionalInfoVisible;
-
-  useEffect(() => {
-    const timerId = setTimeout(() => {
-      if (isAdditionalInfoVisible && (renderDataSource || renderLastEdit)) {
-        setShowSubHeader(false);
-      }
-    }, 4000);
-    return () => clearTimeout(timerId);
-  }, [isAdditionalInfoVisible, renderDataSource, renderLastEdit]);
-
-  return (
-    <SavedQuestionLeftSideRoot
-      data-testid="qb-header-left-side"
-      showSubHeader={showSubHeader}
-    >
-      <ViewHeaderMainLeftContentContainer>
-        <SavedQuestionHeaderButtonContainer isModelOrMetric={isModelOrMetric}>
-          <HeadBreadcrumbs
-            divider={<HeaderDivider>/</HeaderDivider>}
-            parts={[
-              ...(isAdditionalInfoVisible && isModelOrMetric
-                ? [
-                    <HeaderCollectionBadge
-                      key="collection"
-                      question={question}
-                    />,
-                  ]
-                : []),
-
-              <SavedQuestionHeaderButton
-                key={question.displayName()}
-                question={question}
-                onSave={onHeaderChange}
-              />,
-            ]}
-          />
-        </SavedQuestionHeaderButtonContainer>
-      </ViewHeaderMainLeftContentContainer>
-      {isAdditionalInfoVisible && (
-        <ViewHeaderLeftSubHeading>
-          {QuestionDataSource.shouldRender(props) && !isModelOrMetric && (
-            <StyledQuestionDataSource
-              question={question}
-              isObjectDetail={isObjectDetail}
-              subHead
-            />
-          )}
-          {hasLastEditInfo && isAdditionalInfoVisible && (
-            <StyledLastEditInfoLabel
-              item={question.card()}
-              onClick={onOpenQuestionInfo}
-            />
-          )}
-        </ViewHeaderLeftSubHeading>
-      )}
-    </SavedQuestionLeftSideRoot>
-  );
-}
-
-AhHocQuestionLeftSide.propTypes = {
-  question: PropTypes.object.isRequired,
-  originalQuestion: PropTypes.object,
-  isNative: PropTypes.bool,
-  isObjectDetail: PropTypes.bool,
-  isSummarized: PropTypes.bool,
-  onOpenModal: PropTypes.func,
-};
-
-function AhHocQuestionLeftSide(props) {
-  const {
-    question,
-    originalQuestion,
-    isNative,
-    isObjectDetail,
-    isSummarized,
-    onOpenModal,
-  } = props;
-
-  const handleTitleClick = () => {
-    const { isEditable } = Lib.queryDisplayInfo(question.query());
-
-    if (isEditable) {
-      onOpenModal(MODAL_TYPES.SAVE);
-    }
-  };
-
-  return (
-    <AdHocLeftSideRoot>
-      <ViewHeaderMainLeftContentContainer>
-        <AdHocViewHeading color="medium">
-          {isNative ? (
-            t`New question`
-          ) : (
-            <QuestionDescription
-              question={question}
-              originalQuestion={originalQuestion}
-              isObjectDetail={isObjectDetail}
-              onClick={handleTitleClick}
-            />
-          )}
-        </AdHocViewHeading>
-      </ViewHeaderMainLeftContentContainer>
-      <ViewHeaderLeftSubHeading>
-        {isSummarized && (
-          <QuestionDataSource
-            className={CS.mb1}
-            question={question}
-            isObjectDetail={isObjectDetail}
-            subHead
-          />
-        )}
-      </ViewHeaderLeftSubHeading>
-    </AdHocLeftSideRoot>
-  );
-}
-
-HeaderCollectionBadge.propTypes = {
-  question: PropTypes.object.isRequired,
-};
-
-function HeaderCollectionBadge({ question }) {
-  const { collection } = question.card();
-  const icon = question.type();
-  return (
-    <HeadBreadcrumbs.Badge to={Urls.collection(collection)} icon={icon}>
-      {collection?.name || t`Our analytics`}
-    </HeadBreadcrumbs.Badge>
-  );
-}
-
-ViewTitleHeaderRightSide.propTypes = {
-  question: PropTypes.object.isRequired,
-  result: PropTypes.object,
-  queryBuilderMode: PropTypes.oneOf(["view", "notebook"]),
-  isModelOrMetric: PropTypes.bool,
-  isSaved: PropTypes.bool,
-  isNative: PropTypes.bool,
-  isRunnable: PropTypes.bool,
-  isRunning: PropTypes.bool,
-  isNativeEditorOpen: PropTypes.bool,
-  isShowingSummarySidebar: PropTypes.bool,
-  isDirty: PropTypes.bool,
-  isResultDirty: PropTypes.bool,
-  isActionListVisible: PropTypes.bool,
-  runQuestionQuery: PropTypes.func,
-  updateQuestion: PropTypes.func.isRequired,
-  cancelQuery: PropTypes.func,
-  onOpenModal: PropTypes.func,
-  onEditSummary: PropTypes.func,
-  onCloseSummary: PropTypes.func,
-  setQueryBuilderMode: PropTypes.func,
-  turnDatasetIntoQuestion: PropTypes.func,
-  areFiltersExpanded: PropTypes.bool,
-  onExpandFilters: PropTypes.func,
-  onCollapseFilters: PropTypes.func,
-  isBookmarked: PropTypes.bool,
-  toggleBookmark: PropTypes.func,
-  onOpenQuestionInfo: PropTypes.func,
-  onCloseQuestionInfo: PropTypes.func,
-  isShowingQuestionInfoSidebar: PropTypes.bool,
-  onModelPersistenceChange: PropTypes.func,
-  onQueryChange: PropTypes.func,
-};
-
-function ViewTitleHeaderRightSide(props) {
-  const {
-    question,
-    result,
-    queryBuilderMode,
-    isBookmarked,
-    toggleBookmark,
-    isSaved,
-    isModelOrMetric,
-    isRunnable,
-    isRunning,
-    isNativeEditorOpen,
-    isShowingSummarySidebar,
-    isDirty,
-    isResultDirty,
-    isActionListVisible,
-    runQuestionQuery,
-    cancelQuery,
-    onOpenModal,
-    onEditSummary,
-    onCloseSummary,
-    setQueryBuilderMode,
-    turnDatasetIntoQuestion,
-    areFiltersExpanded,
-    onExpandFilters,
-    onCollapseFilters,
-    isShowingQuestionInfoSidebar,
-    onCloseQuestionInfo,
-    onOpenQuestionInfo,
-    onModelPersistenceChange,
-  } = props;
-  const isShowingNotebook = queryBuilderMode === "notebook";
-  const { isEditable } = Lib.queryDisplayInfo(question.query());
-
-  const hasExploreResultsLink =
-    canExploreResults(question) &&
-    MetabaseSettings.get("enable-nested-queries");
-
-  // Models and metrics can't be saved. But changing anything about the model/metric will prompt the user
-  // to save it as a new question (based on that model/metric). In other words, at this point
-  // the `type` field is set to "question".
-  const hasSaveButton =
-    !isModelOrMetric &&
-    !!isDirty &&
-    !question.isArchived() &&
-    isActionListVisible;
-  const isMissingPermissions =
-    result?.error_type === SERVER_ERROR_TYPES.missingPermissions;
-  const hasRunButton =
-    isRunnable && !isNativeEditorOpen && !isMissingPermissions;
-
-  const handleInfoClick = useCallback(() => {
-    if (isShowingQuestionInfoSidebar) {
-      onCloseQuestionInfo();
-    } else {
-      onOpenQuestionInfo();
-    }
-  }, [isShowingQuestionInfoSidebar, onOpenQuestionInfo, onCloseQuestionInfo]);
-
-  const getRunButtonLabel = useCallback(
-    () => (isRunning ? t`Cancel` : t`Refresh`),
-    [isRunning],
-  );
-
-  const canSave = Lib.canSave(question.query(), question.type());
-  const isSaveDisabled = !canSave;
-  const disabledSaveTooltip = getDisabledSaveTooltip(isEditable);
-
-  return (
-    <ViewHeaderActionPanel data-testid="qb-header-action-panel">
-      {FilterHeaderToggle.shouldRender(props) && (
-        <FilterHeaderToggle
-          className={cx(CS.ml2, CS.mr1)}
-          query={question.query()}
-          isExpanded={areFiltersExpanded}
-          onExpand={onExpandFilters}
-          onCollapse={onCollapseFilters}
-        />
-      )}
-      {FilterHeaderButton.shouldRender(props) && (
-        <FilterHeaderButton
-          className={cx(CS.hide, CS.smShow)}
-          onOpenModal={onOpenModal}
-        />
-      )}
-      {QuestionSummarizeWidget.shouldRender(props) && (
-        <QuestionSummarizeWidget
-          className={cx(CS.hide, CS.smShow)}
-          isShowingSummarySidebar={isShowingSummarySidebar}
-          onEditSummary={onEditSummary}
-          onCloseSummary={onCloseSummary}
-        />
-      )}
-      {QuestionNotebookButton.shouldRender(props) && (
-        <ViewHeaderIconButtonContainer>
-          <QuestionNotebookButton
-            iconSize={16}
-            question={question}
-            isShowingNotebook={isShowingNotebook}
-            setQueryBuilderMode={setQueryBuilderMode}
-          />
-        </ViewHeaderIconButtonContainer>
-      )}
-      {ToggleNativeQueryPreview.shouldRender(props) && (
-        <ToggleNativeQueryPreview question={question} />
-      )}
-      {hasExploreResultsLink && <ExploreResultsLink question={question} />}
-      {hasRunButton && !isShowingNotebook && (
-        <ViewHeaderIconButtonContainer>
-          <ViewRunButtonWithTooltip
-            iconSize={16}
-            onlyIcon
-            medium
-            compact
-            result={result}
-            isRunning={isRunning}
-            isDirty={isResultDirty}
-            onRun={() => runQuestionQuery({ ignoreCache: true })}
-            onCancel={cancelQuery}
-            getTooltip={getRunButtonLabel}
-          />
-        </ViewHeaderIconButtonContainer>
-      )}
-      {isSaved && (
-        <QuestionActions
-          isShowingQuestionInfoSidebar={isShowingQuestionInfoSidebar}
-          isBookmarked={isBookmarked}
-          handleBookmark={toggleBookmark}
-          onOpenModal={onOpenModal}
-          question={question}
-          setQueryBuilderMode={setQueryBuilderMode}
-          turnDatasetIntoQuestion={turnDatasetIntoQuestion}
-          onInfoClick={handleInfoClick}
-          onModelPersistenceChange={onModelPersistenceChange}
-        />
-      )}
-      {hasSaveButton && (
-        <SaveButton
-          role="button"
-          disabled={isSaveDisabled}
-          tooltip={{
-            tooltip: disabledSaveTooltip,
-            isEnabled: isSaveDisabled,
-            placement: "left",
-          }}
-          onClick={() => onOpenModal("save")}
-        >
-          {t`Save`}
-        </SaveButton>
-      )}
-    </ViewHeaderActionPanel>
-  );
-}
-
 ViewTitleHeader.propTypes = viewTitleHeaderPropTypes;
-
-function getDisabledSaveTooltip(isEditable) {
-  if (!isEditable) {
-    return t`You don't have permission to save this question.`;
-  }
-}
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/AdHocQuestionLeftSide/AdHocQuestionLeftSide.jsx b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/AdHocQuestionLeftSide/AdHocQuestionLeftSide.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..e6a37049622163a5627bf0e368632317273f5e3c
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/AdHocQuestionLeftSide/AdHocQuestionLeftSide.jsx
@@ -0,0 +1,72 @@
+import PropTypes from "prop-types";
+import { t } from "ttag";
+
+import CS from "metabase/css/core/index.css";
+import {
+  AdHocLeftSideRoot,
+  AdHocViewHeading,
+  ViewHeaderLeftSubHeading,
+  ViewHeaderMainLeftContentContainer,
+} from "metabase/query_builder/components/view/ViewHeader/ViewHeader.styled";
+import {
+  QuestionDataSource,
+  QuestionDescription,
+} from "metabase/query_builder/components/view/ViewHeader/components";
+import { MODAL_TYPES } from "metabase/query_builder/constants";
+import * as Lib from "metabase-lib";
+
+AdHocQuestionLeftSide.propTypes = {
+  question: PropTypes.object.isRequired,
+  originalQuestion: PropTypes.object,
+  isNative: PropTypes.bool,
+  isObjectDetail: PropTypes.bool,
+  isSummarized: PropTypes.bool,
+  onOpenModal: PropTypes.func,
+};
+export function AdHocQuestionLeftSide(props) {
+  const {
+    question,
+    originalQuestion,
+    isNative,
+    isObjectDetail,
+    isSummarized,
+    onOpenModal,
+  } = props;
+
+  const handleTitleClick = () => {
+    const { isEditable } = Lib.queryDisplayInfo(question.query());
+
+    if (isEditable) {
+      onOpenModal(MODAL_TYPES.SAVE);
+    }
+  };
+
+  return (
+    <AdHocLeftSideRoot>
+      <ViewHeaderMainLeftContentContainer>
+        <AdHocViewHeading color="medium">
+          {isNative ? (
+            t`New question`
+          ) : (
+            <QuestionDescription
+              question={question}
+              originalQuestion={originalQuestion}
+              isObjectDetail={isObjectDetail}
+              onClick={handleTitleClick}
+            />
+          )}
+        </AdHocViewHeading>
+      </ViewHeaderMainLeftContentContainer>
+      <ViewHeaderLeftSubHeading>
+        {isSummarized && (
+          <QuestionDataSource
+            className={CS.mb1}
+            question={question}
+            isObjectDetail={isObjectDetail}
+            subHead
+          />
+        )}
+      </ViewHeaderLeftSubHeading>
+    </AdHocLeftSideRoot>
+  );
+}
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/AdHocQuestionLeftSide/index.ts b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/AdHocQuestionLeftSide/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d04e1a9ccda4eb95040dbfeb47a74bf573ae9ca9
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/AdHocQuestionLeftSide/index.ts
@@ -0,0 +1 @@
+export * from "./AdHocQuestionLeftSide";
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/DashboardBackButton/DashboardBackButton.tsx b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/DashboardBackButton/DashboardBackButton.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..2624af64af84f38fd2b17bba48d49122632e2b9c
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/DashboardBackButton/DashboardBackButton.tsx
@@ -0,0 +1,42 @@
+import { t } from "ttag";
+
+import Link from "metabase/core/components/Link";
+import Tooltip from "metabase/core/components/Tooltip";
+import { useDispatch, useSelector } from "metabase/lib/redux";
+import * as Urls from "metabase/lib/urls";
+import { navigateBackToDashboard } from "metabase/query_builder/actions";
+import {
+  BackButton,
+  BackButtonContainer,
+} from "metabase/query_builder/components/view/ViewHeader/ViewHeader.styled";
+import { getDashboard } from "metabase/query_builder/selectors";
+
+export function DashboardBackButton() {
+  const dashboard = useSelector(getDashboard);
+  const dispatch = useDispatch();
+
+  const handleClick = () => {
+    dispatch(navigateBackToDashboard(dashboard.id));
+  };
+
+  if (!dashboard) {
+    return null;
+  }
+
+  const label = t`Back to ${dashboard.name}`;
+
+  return (
+    <Tooltip tooltip={label}>
+      <BackButtonContainer>
+        <BackButton
+          as={Link}
+          to={Urls.dashboard(dashboard)}
+          round
+          icon="arrow_left"
+          aria-label={label}
+          onClick={handleClick}
+        />
+      </BackButtonContainer>
+    </Tooltip>
+  );
+}
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/DashboardBackButton/index.ts b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/DashboardBackButton/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..08325e8af35f427588533c7cfad11054be3a4691
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/DashboardBackButton/index.ts
@@ -0,0 +1 @@
+export * from "./DashboardBackButton";
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderCollectionBadge/HeaderCollectionBadge.jsx b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderCollectionBadge/HeaderCollectionBadge.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..4f3871b004a1fcb19bfb7591baa615e551f6ab71
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderCollectionBadge/HeaderCollectionBadge.jsx
@@ -0,0 +1,19 @@
+import PropTypes from "prop-types";
+import { t } from "ttag";
+
+import * as Urls from "metabase/lib/urls";
+import { HeadBreadcrumbs } from "metabase/query_builder/components/view/ViewHeader/components";
+
+HeaderCollectionBadge.propTypes = {
+  question: PropTypes.object.isRequired,
+};
+
+export function HeaderCollectionBadge({ question }) {
+  const { collection } = question.card();
+  const icon = question.type();
+  return (
+    <HeadBreadcrumbs.Badge to={Urls.collection(collection)} icon={icon}>
+      {collection?.name || t`Our analytics`}
+    </HeadBreadcrumbs.Badge>
+  );
+}
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderCollectionBadge/index.ts b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderCollectionBadge/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..edec7552da21334520db52bd54bc198267c90688
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderCollectionBadge/index.ts
@@ -0,0 +1 @@
+export * from "./HeaderCollectionBadge";
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/SavedQuestionLeftSide/SavedQuestionLeftSide.jsx b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/SavedQuestionLeftSide/SavedQuestionLeftSide.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..9c10c47202f14b7dd63334f88b534c206462cb29
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/SavedQuestionLeftSide/SavedQuestionLeftSide.jsx
@@ -0,0 +1,112 @@
+import PropTypes from "prop-types";
+import { useCallback, useEffect, useState } from "react";
+
+import SavedQuestionHeaderButton from "metabase/query_builder/components/SavedQuestionHeaderButton/SavedQuestionHeaderButton";
+import {
+  HeaderDivider,
+  SavedQuestionHeaderButtonContainer,
+  SavedQuestionLeftSideRoot,
+  StyledLastEditInfoLabel,
+  StyledQuestionDataSource,
+  ViewHeaderLeftSubHeading,
+  ViewHeaderMainLeftContentContainer,
+} from "metabase/query_builder/components/view/ViewHeader/ViewHeader.styled";
+import {
+  HeadBreadcrumbs,
+  QuestionDataSource,
+} from "metabase/query_builder/components/view/ViewHeader/components";
+import { HeaderCollectionBadge } from "metabase/query_builder/components/view/ViewHeader/components/HeaderCollectionBadge/HeaderCollectionBadge";
+
+SavedQuestionLeftSide.propTypes = {
+  question: PropTypes.object.isRequired,
+  isObjectDetail: PropTypes.bool,
+  isAdditionalInfoVisible: PropTypes.bool,
+  isShowingQuestionDetailsSidebar: PropTypes.bool,
+  onOpenQuestionInfo: PropTypes.func.isRequired,
+  onSave: PropTypes.func,
+};
+export function SavedQuestionLeftSide(props) {
+  const {
+    question,
+    isObjectDetail,
+    isAdditionalInfoVisible,
+    onOpenQuestionInfo,
+    onSave,
+  } = props;
+
+  const [showSubHeader, setShowSubHeader] = useState(true);
+
+  const hasLastEditInfo = question.lastEditInfo() != null;
+  const type = question.type();
+  const isModelOrMetric = type === "model" || type === "metric";
+
+  const onHeaderChange = useCallback(
+    name => {
+      if (name && name !== question.displayName()) {
+        onSave(question.setDisplayName(name));
+      }
+    },
+    [question, onSave],
+  );
+
+  const renderDataSource =
+    QuestionDataSource.shouldRender(props) && type === "question";
+  const renderLastEdit = hasLastEditInfo && isAdditionalInfoVisible;
+
+  useEffect(() => {
+    const timerId = setTimeout(() => {
+      if (isAdditionalInfoVisible && (renderDataSource || renderLastEdit)) {
+        setShowSubHeader(false);
+      }
+    }, 4000);
+    return () => clearTimeout(timerId);
+  }, [isAdditionalInfoVisible, renderDataSource, renderLastEdit]);
+
+  return (
+    <SavedQuestionLeftSideRoot
+      data-testid="qb-header-left-side"
+      showSubHeader={showSubHeader}
+    >
+      <ViewHeaderMainLeftContentContainer>
+        <SavedQuestionHeaderButtonContainer isModelOrMetric={isModelOrMetric}>
+          <HeadBreadcrumbs
+            divider={<HeaderDivider>/</HeaderDivider>}
+            parts={[
+              ...(isAdditionalInfoVisible && isModelOrMetric
+                ? [
+                    <HeaderCollectionBadge
+                      key="collection"
+                      question={question}
+                    />,
+                  ]
+                : []),
+
+              <SavedQuestionHeaderButton
+                key={question.displayName()}
+                question={question}
+                onSave={onHeaderChange}
+              />,
+            ]}
+          />
+        </SavedQuestionHeaderButtonContainer>
+      </ViewHeaderMainLeftContentContainer>
+      {isAdditionalInfoVisible && (
+        <ViewHeaderLeftSubHeading>
+          {QuestionDataSource.shouldRender(props) && !isModelOrMetric && (
+            <StyledQuestionDataSource
+              question={question}
+              isObjectDetail={isObjectDetail}
+              subHead
+            />
+          )}
+          {hasLastEditInfo && isAdditionalInfoVisible && (
+            <StyledLastEditInfoLabel
+              item={question.card()}
+              onClick={onOpenQuestionInfo}
+            />
+          )}
+        </ViewHeaderLeftSubHeading>
+      )}
+    </SavedQuestionLeftSideRoot>
+  );
+}
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/SavedQuestionLeftSide/index.ts b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/SavedQuestionLeftSide/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..50bff38e34182e84e3da9166efa37e3ccbfc2f62
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/SavedQuestionLeftSide/index.ts
@@ -0,0 +1 @@
+export * from "./SavedQuestionLeftSide";
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/ViewTitleHeaderRightSide/ViewTitleHeaderRightSide.jsx b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/ViewTitleHeaderRightSide/ViewTitleHeaderRightSide.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..4ba23c52b8d45ddc7bd2eed0d4a1a7c3e993a570
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/ViewTitleHeaderRightSide/ViewTitleHeaderRightSide.jsx
@@ -0,0 +1,219 @@
+import cx from "classnames";
+import PropTypes from "prop-types";
+import { useCallback } from "react";
+import { t } from "ttag";
+
+import CS from "metabase/css/core/index.css";
+import { SERVER_ERROR_TYPES } from "metabase/lib/errors";
+import MetabaseSettings from "metabase/lib/settings";
+import {
+  SaveButton,
+  ViewHeaderActionPanel,
+  ViewHeaderIconButtonContainer,
+  ViewRunButtonWithTooltip,
+} from "metabase/query_builder/components/view/ViewHeader/ViewHeader.styled";
+import {
+  ExploreResultsLink,
+  FilterHeaderButton,
+  FilterHeaderToggle,
+  QuestionActions,
+  QuestionNotebookButton,
+  QuestionSummarizeWidget,
+  ToggleNativeQueryPreview,
+} from "metabase/query_builder/components/view/ViewHeader/components";
+import { canExploreResults } from "metabase/query_builder/components/view/ViewHeader/utils";
+import * as Lib from "metabase-lib";
+
+ViewTitleHeaderRightSide.propTypes = {
+  question: PropTypes.object.isRequired,
+  result: PropTypes.object,
+  queryBuilderMode: PropTypes.oneOf(["view", "notebook"]),
+  isModelOrMetric: PropTypes.bool,
+  isSaved: PropTypes.bool,
+  isNative: PropTypes.bool,
+  isRunnable: PropTypes.bool,
+  isRunning: PropTypes.bool,
+  isNativeEditorOpen: PropTypes.bool,
+  isShowingSummarySidebar: PropTypes.bool,
+  isDirty: PropTypes.bool,
+  isResultDirty: PropTypes.bool,
+  isActionListVisible: PropTypes.bool,
+  runQuestionQuery: PropTypes.func,
+  updateQuestion: PropTypes.func.isRequired,
+  cancelQuery: PropTypes.func,
+  onOpenModal: PropTypes.func,
+  onEditSummary: PropTypes.func,
+  onCloseSummary: PropTypes.func,
+  setQueryBuilderMode: PropTypes.func,
+  turnDatasetIntoQuestion: PropTypes.func,
+  areFiltersExpanded: PropTypes.bool,
+  onExpandFilters: PropTypes.func,
+  onCollapseFilters: PropTypes.func,
+  isBookmarked: PropTypes.bool,
+  toggleBookmark: PropTypes.func,
+  onOpenQuestionInfo: PropTypes.func,
+  onCloseQuestionInfo: PropTypes.func,
+  isShowingQuestionInfoSidebar: PropTypes.bool,
+  onModelPersistenceChange: PropTypes.func,
+  onQueryChange: PropTypes.func,
+};
+
+export function ViewTitleHeaderRightSide(props) {
+  const {
+    question,
+    result,
+    queryBuilderMode,
+    isBookmarked,
+    toggleBookmark,
+    isSaved,
+    isModelOrMetric,
+    isRunnable,
+    isRunning,
+    isNativeEditorOpen,
+    isShowingSummarySidebar,
+    isDirty,
+    isResultDirty,
+    isActionListVisible,
+    runQuestionQuery,
+    cancelQuery,
+    onOpenModal,
+    onEditSummary,
+    onCloseSummary,
+    setQueryBuilderMode,
+    turnDatasetIntoQuestion,
+    areFiltersExpanded,
+    onExpandFilters,
+    onCollapseFilters,
+    isShowingQuestionInfoSidebar,
+    onCloseQuestionInfo,
+    onOpenQuestionInfo,
+    onModelPersistenceChange,
+  } = props;
+  const isShowingNotebook = queryBuilderMode === "notebook";
+  const { isEditable } = Lib.queryDisplayInfo(question.query());
+
+  const hasExploreResultsLink =
+    canExploreResults(question) &&
+    MetabaseSettings.get("enable-nested-queries");
+
+  // Models and metrics can't be saved. But changing anything about the model/metric will prompt the user
+  // to save it as a new question (based on that model/metric). In other words, at this point
+  // the `type` field is set to "question".
+  const hasSaveButton =
+    !isModelOrMetric &&
+    !!isDirty &&
+    !question.isArchived() &&
+    isActionListVisible;
+  const isMissingPermissions =
+    result?.error_type === SERVER_ERROR_TYPES.missingPermissions;
+  const hasRunButton =
+    isRunnable && !isNativeEditorOpen && !isMissingPermissions;
+
+  const handleInfoClick = useCallback(() => {
+    if (isShowingQuestionInfoSidebar) {
+      onCloseQuestionInfo();
+    } else {
+      onOpenQuestionInfo();
+    }
+  }, [isShowingQuestionInfoSidebar, onOpenQuestionInfo, onCloseQuestionInfo]);
+
+  const getRunButtonLabel = useCallback(
+    () => (isRunning ? t`Cancel` : t`Refresh`),
+    [isRunning],
+  );
+
+  const canSave = Lib.canSave(question.query(), question.type());
+  const isSaveDisabled = !canSave;
+  const disabledSaveTooltip = getDisabledSaveTooltip(isEditable);
+
+  return (
+    <ViewHeaderActionPanel data-testid="qb-header-action-panel">
+      {FilterHeaderToggle.shouldRender(props) && (
+        <FilterHeaderToggle
+          className={cx(CS.ml2, CS.mr1)}
+          query={question.query()}
+          isExpanded={areFiltersExpanded}
+          onExpand={onExpandFilters}
+          onCollapse={onCollapseFilters}
+        />
+      )}
+      {FilterHeaderButton.shouldRender(props) && (
+        <FilterHeaderButton
+          className={cx(CS.hide, CS.smShow)}
+          onOpenModal={onOpenModal}
+        />
+      )}
+      {QuestionSummarizeWidget.shouldRender(props) && (
+        <QuestionSummarizeWidget
+          className={cx(CS.hide, CS.smShow)}
+          isShowingSummarySidebar={isShowingSummarySidebar}
+          onEditSummary={onEditSummary}
+          onCloseSummary={onCloseSummary}
+        />
+      )}
+      {QuestionNotebookButton.shouldRender(props) && (
+        <ViewHeaderIconButtonContainer>
+          <QuestionNotebookButton
+            iconSize={16}
+            question={question}
+            isShowingNotebook={isShowingNotebook}
+            setQueryBuilderMode={setQueryBuilderMode}
+          />
+        </ViewHeaderIconButtonContainer>
+      )}
+      {ToggleNativeQueryPreview.shouldRender(props) && (
+        <ToggleNativeQueryPreview question={question} />
+      )}
+      {hasExploreResultsLink && <ExploreResultsLink question={question} />}
+      {hasRunButton && !isShowingNotebook && (
+        <ViewHeaderIconButtonContainer>
+          <ViewRunButtonWithTooltip
+            iconSize={16}
+            onlyIcon
+            medium
+            compact
+            result={result}
+            isRunning={isRunning}
+            isDirty={isResultDirty}
+            onRun={() => runQuestionQuery({ ignoreCache: true })}
+            onCancel={cancelQuery}
+            getTooltip={getRunButtonLabel}
+          />
+        </ViewHeaderIconButtonContainer>
+      )}
+      {isSaved && (
+        <QuestionActions
+          isShowingQuestionInfoSidebar={isShowingQuestionInfoSidebar}
+          isBookmarked={isBookmarked}
+          handleBookmark={toggleBookmark}
+          onOpenModal={onOpenModal}
+          question={question}
+          setQueryBuilderMode={setQueryBuilderMode}
+          turnDatasetIntoQuestion={turnDatasetIntoQuestion}
+          onInfoClick={handleInfoClick}
+          onModelPersistenceChange={onModelPersistenceChange}
+        />
+      )}
+      {hasSaveButton && (
+        <SaveButton
+          role="button"
+          disabled={isSaveDisabled}
+          tooltip={{
+            tooltip: disabledSaveTooltip,
+            isEnabled: isSaveDisabled,
+            placement: "left",
+          }}
+          onClick={() => onOpenModal("save")}
+        >
+          {t`Save`}
+        </SaveButton>
+      )}
+    </ViewHeaderActionPanel>
+  );
+}
+
+function getDisabledSaveTooltip(isEditable) {
+  if (!isEditable) {
+    return t`You don't have permission to save this question.`;
+  }
+}
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/ViewTitleHeaderRightSide/index.ts b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/ViewTitleHeaderRightSide/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7d54488ba51cafc782781b8f8b705d707868e29d
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/ViewTitleHeaderRightSide/index.ts
@@ -0,0 +1 @@
+export * from "./ViewTitleHeaderRightSide";
diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/index.ts b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/index.ts
index 041d9ab751b3c12b1bd0332410fe8f56db2456ec..a5afae841810f69499b3e5760e48813f2f9b7f04 100644
--- a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/index.ts
+++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/index.ts
@@ -8,3 +8,8 @@ export * from "./QuestionNotebookButton";
 export * from "./ExploreResultsLink";
 export * from "./FilterHeaderButton";
 export * from "./QuestionSummarizeWidget";
+export * from "./AdHocQuestionLeftSide";
+export * from "./HeaderCollectionBadge";
+export * from "./SavedQuestionLeftSide";
+export * from "./ViewTitleHeaderRightSide";
+export * from "./DashboardBackButton";