From 21816542aa023f37aa7ef82a5bd37040fd5e657a Mon Sep 17 00:00:00 2001 From: Ryan Laurie <30528226+iethree@users.noreply.github.com> Date: Fri, 17 Feb 2023 09:47:28 -0700 Subject: [PATCH] Disable action buttons when actions are disabled on a db (#28364) * disable action buttons when actions are disabled on a db * destructure props --- .../actions/components/ActionViz/Action.tsx | 21 +++++++- .../components/ActionViz/Action.unit.spec.tsx | 49 ++++++++++++++++++- .../components/ActionViz/ActionButtonView.tsx | 1 + 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/frontend/src/metabase/actions/components/ActionViz/Action.tsx b/frontend/src/metabase/actions/components/ActionViz/Action.tsx index cffd6d9847a..bb689f38b3d 100644 --- a/frontend/src/metabase/actions/components/ActionViz/Action.tsx +++ b/frontend/src/metabase/actions/components/ActionViz/Action.tsx @@ -20,6 +20,9 @@ import { } from "metabase/actions/utils"; import { getEditingDashcardId } from "metabase/dashboard/selectors"; +import { getMetadata } from "metabase/selectors/metadata"; +import type Metadata from "metabase-lib/metadata/Metadata"; + import { getDashcardParamValues, getNotProvidedActionParameters, @@ -34,6 +37,7 @@ export interface ActionProps extends VisualizationProps { dispatch: Dispatch; parameterValues: { [id: string]: ParameterValueOrArray }; isEditingDashcard: boolean; + metadata: Metadata; } export function ActionComponent({ @@ -116,16 +120,29 @@ const ConnectedActionComponent = connect()(ActionComponent); function mapStateToProps(state: State, props: ActionProps) { return { isEditingDashcard: getEditingDashcardId(state) === props.dashcard.id, + metadata: getMetadata(state), }; } export function ActionFn(props: ActionProps) { - if (!props.dashcard?.action) { + const { + metadata, + dashcard: { action }, + } = props; + const actionsEnabled = !!metadata + ?.database(action?.database_id) + ?.hasActionsEnabled?.(); + + if (!props.dashcard?.action || !actionsEnabled) { + const tooltip = !action + ? t`No action assigned` + : t`Actions are not enabled for this database`; + return ( <ActionButtonView disabled icon="bolt" - tooltip={t`No action assigned`} + tooltip={tooltip} settings={props.settings} focus={props.isEditingDashcard} /> diff --git a/frontend/src/metabase/actions/components/ActionViz/Action.unit.spec.tsx b/frontend/src/metabase/actions/components/ActionViz/Action.unit.spec.tsx index e53750935cf..45d86836f3e 100644 --- a/frontend/src/metabase/actions/components/ActionViz/Action.unit.spec.tsx +++ b/frontend/src/metabase/actions/components/ActionViz/Action.unit.spec.tsx @@ -11,6 +11,7 @@ import { createMockQueryAction, createMockImplicitQueryAction, createMockDashboard, + createMockDatabase, } from "metabase-types/api/mocks"; import Action, { ActionComponent, ActionProps } from "./Action"; @@ -21,6 +22,7 @@ const defaultProps = { card_id: 777, // action model id action: createMockQueryAction({ name: "My Awesome Action", + database_id: 2, parameters: [ createMockActionParameter({ id: "1", @@ -65,7 +67,20 @@ async function setup(options?: Partial<ActionProps>) { } async function setupActionWrapper(options?: Partial<ActionProps>) { - return renderWithProviders(<Action {...defaultProps} {...options} />); + return renderWithProviders(<Action {...defaultProps} {...options} />, { + withSampleDatabase: true, + storeInitialState: { + entities: { + databases: { + 1: createMockDatabase({ id: 1 }), + 2: createMockDatabase({ + id: 2, + settings: { "database-enable-actions": true }, + }), + }, + }, + }, + }); } function setupExecutionEndpoint(expectedBody: any) { @@ -91,6 +106,38 @@ describe("Actions > ActionViz > ActionComponent", () => { }, }); expect(screen.getByLabelText("bolt icon")).toBeInTheDocument(); + expect(screen.getByRole("button")).toBeDisabled(); + expect(screen.getByLabelText(/no action assigned/i)).toBeInTheDocument(); + }); + + it("should render a disabled state for a button with an action from a database where actions are disabled", async () => { + await setupActionWrapper({ + dashcard: { + ...defaultProps.dashcard, + action: createMockQueryAction({ + name: "My Awesome Action", + database_id: 1, + }), + }, + }); + expect(screen.getByLabelText("bolt icon")).toBeInTheDocument(); + expect(screen.getByRole("button")).toBeDisabled(); + expect( + screen.getByLabelText(/actions are not enabled/i), + ).toBeInTheDocument(); + }); + + it("should render an enabled state when the action is valid", async () => { + await setupActionWrapper({ + dashcard: { + ...defaultProps.dashcard, + action: createMockQueryAction({ + name: "My Awesome Action", + database_id: 2, + }), + }, + }); + expect(screen.getByRole("button")).toBeEnabled(); }); it("should render a button with default text", async () => { diff --git a/frontend/src/metabase/actions/components/ActionViz/ActionButtonView.tsx b/frontend/src/metabase/actions/components/ActionViz/ActionButtonView.tsx index 2532a33b9ff..f33d30c8c05 100644 --- a/frontend/src/metabase/actions/components/ActionViz/ActionButtonView.tsx +++ b/frontend/src/metabase/actions/components/ActionViz/ActionButtonView.tsx @@ -39,6 +39,7 @@ function ActionButtonView({ onClick={onClick} isFullHeight={isFullHeight} focus={focus} + aria-label={tooltip} {...variantProps} > <StyledButtonContent> -- GitLab