Skip to content
Snippets Groups Projects
Unverified Commit 4047d878 authored by github-automation-metabase's avatar github-automation-metabase Committed by GitHub
Browse files

48049 error diagnostic command palette (#48544) (#48590)


* Moving diagnostic state to redux, adding CP action

* changing key binding

* adding e2e test

* adjusting e2e test

* type adjustment

Co-authored-by: default avatarNick Fitzpatrick <nick@metabase.com>
parent 1b59f0db
No related branches found
No related tags found
No related merge requests found
......@@ -30,3 +30,5 @@ export const commandPaletteSearch = (query, viewAll = true) => {
.click();
}
};
export const commandPaletteAction = name => cy.findByRole("option", { name });
import { ORDERS_DASHBOARD_ID } from "e2e/support/cypress_sample_instance_data";
import {
commandPaletteAction,
commandPaletteButton,
commandPaletteInput,
createQuestion,
modal,
restore,
......@@ -42,6 +45,24 @@ describe("error reporting modal", () => {
});
});
it("should allow you to open the error reporting modal via the command palette", () => {
restore();
cy.signInAsAdmin();
cy.visit("/");
cy.findByTestId("home-page")
.findByText(/see what metabase can do/i)
.should("exist");
commandPaletteButton().click();
commandPaletteInput().type("Error");
commandPaletteAction(/Open error diagnostic modal/).click();
cy.findByRole("dialog", { name: "Download diagnostic information" }).should(
"be.visible",
);
});
it("should not show error reporting modal in embedding", () => {
restore();
cy.signInAsAdmin();
......
......@@ -76,7 +76,7 @@ describe("command palette", () => {
// When entering a query, if there are results that come before search results, highlight
// the first action, otherwise, highlight the first search result
commandPaletteInput().clear().type("Or");
commandPaletteInput().clear().type("For");
cy.findByRole("option", { name: "Performance" }).should(
"have.attr",
"aria-selected",
......
......@@ -18,4 +18,5 @@ export interface AppState {
errorPage: AppErrorDescriptor | null;
isNavbarOpen: boolean;
isDndAvailable: boolean;
isErrorDiagnosticsOpen: boolean;
}
......@@ -4,5 +4,6 @@ export const createMockAppState = (opts?: Partial<AppState>): AppState => ({
isNavbarOpen: true,
errorPage: null,
isDndAvailable: false,
isErrorDiagnosticsOpen: false,
...opts,
});
import { useEffect, useState } from "react";
import { useState } from "react";
import { c, t } from "ttag";
import _ from "underscore";
......@@ -12,6 +12,9 @@ import {
} from "metabase/forms";
import { useToggle } from "metabase/hooks/use-toggle";
import { capitalize } from "metabase/lib/formatting";
import { useDispatch, useSelector } from "metabase/lib/redux";
import { closeDiagnostics } from "metabase/redux/app";
import { getIsErrorDiagnosticModalOpen } from "metabase/selectors/app";
import { getIsEmbedded } from "metabase/selectors/embed";
import { Button, Flex, Icon, Loader, Modal, Stack, Text } from "metabase/ui";
......@@ -253,30 +256,12 @@ export const ErrorExplanationModal = ({
};
export const KeyboardTriggeredErrorModal = () => {
const [
isShowingDiagnosticModal,
{ turnOn: openDiagnosticModal, turnOff: closeDiagnosticModal },
] = useToggle(false);
const dispatch = useDispatch();
const isShowingDiagnosticModal = useSelector(getIsErrorDiagnosticModalOpen);
useEffect(() => {
if (getIsEmbedded()) {
return;
}
const keyboardListener = (event: KeyboardEvent) => {
if (
event.key === "F1" &&
(event.ctrlKey || event.metaKey) &&
!event.shiftKey &&
!event.altKey
) {
openDiagnosticModal();
}
};
window.addEventListener("keydown", keyboardListener);
return () => {
window.removeEventListener("keydown", keyboardListener);
};
}, [openDiagnosticModal]);
const handleCloseModal = () => {
dispatch(closeDiagnostics());
};
const {
value: errorInfo,
......@@ -293,7 +278,7 @@ export const KeyboardTriggeredErrorModal = () => {
<ErrorDiagnosticModal
loading={loading}
errorInfo={errorInfo}
onClose={closeDiagnosticModal}
onClose={handleCloseModal}
/>
</ErrorBoundary>
);
......
......@@ -11,6 +11,7 @@ import {
import Collections from "metabase/entities/collections/collections";
import { useDispatch, useSelector } from "metabase/lib/redux";
import * as Urls from "metabase/lib/urls";
import { openDiagnostics } from "metabase/redux/app";
import { closeModal, setOpenModal } from "metabase/redux/ui";
import {
getHasDataAccess,
......@@ -186,7 +187,18 @@ export const useCommandPaletteBasicActions = ({
},
];
return [...actions, ...browseActions];
const diagnosticAction = {
id: "diagnostic_modal",
name: t`Open error diagnostic modal`,
section: "basic",
icon: "info",
shortcut: ["$mod+f1"],
perform: () => {
dispatch(openDiagnostics());
},
};
return [...actions, ...browseActions, diagnosticAction];
}, [
dispatch,
hasDataAccess,
......
......@@ -93,6 +93,20 @@ const isNavbarOpen = handleActions(
true,
);
export const OPEN_DIAGNOSTICS = "metabase/app/OPEN_DIAGNOSTIC_MODAL";
export const CLOSE_DIAGNOSTICS = "metabase/app/CLOSE_DIAGNOSTIC_MODAL";
export const openDiagnostics = createAction(OPEN_DIAGNOSTICS);
export const closeDiagnostics = createAction(CLOSE_DIAGNOSTICS);
const isErrorDiagnosticsOpen = handleActions(
{
[OPEN_DIAGNOSTICS]: () => true,
[CLOSE_DIAGNOSTICS]: () => false,
},
false,
);
// eslint-disable-next-line import/no-default-export -- deprecated usage
export default combineReducers({
errorPage,
......@@ -103,4 +117,5 @@ export default combineReducers({
}
return true;
},
isErrorDiagnosticsOpen,
});
......@@ -224,3 +224,6 @@ export const getCustomHomePageDashboardId = createSelector(
export const getHasDismissedCustomHomePageToast = (state: State) => {
return getSetting(state, "dismissed-custom-dashboard-toast");
};
export const getIsErrorDiagnosticModalOpen = (state: State) =>
state.app.isErrorDiagnosticsOpen;
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