diff --git a/e2e/test/scenarios/sharing/alert/email-alert.cy.spec.js b/e2e/test/scenarios/sharing/alert/email-alert.cy.spec.js index 1d5ffc8e4effc97bd072b89228ec14e4271f09cd..95fd31f1c25bd925f29f604eeab79bb6910c776e 100644 --- a/e2e/test/scenarios/sharing/alert/email-alert.cy.spec.js +++ b/e2e/test/scenarios/sharing/alert/email-alert.cy.spec.js @@ -1,8 +1,17 @@ -import { restore, setupSMTP, visitQuestion } from "e2e/support/helpers"; +import { + restore, + setupSMTP, + visitQuestion, + startNewQuestion, + popover, + visualize, + modal, +} from "e2e/support/helpers"; describe("scenarios > alert > email_alert", { tags: "@external" }, () => { beforeEach(() => { cy.intercept("POST", "/api/alert").as("savedAlert"); + cy.intercept("GET", "/api/card/*").as("card"); restore(); cy.signInAsAdmin(); @@ -47,6 +56,36 @@ describe("scenarios > alert > email_alert", { tags: "@external" }, () => { expect(body.channels[0].enabled).to.eq(false); }); }); + + it("should set up an email alert for newly created question", () => { + startNewQuestion(); + + popover().within(() => { + cy.contains("Sample Database").click(); + cy.contains("People").click(); + }); + + visualize(); + + cy.icon("bell").click(); + + cy.findByRole("dialog").within(() => { + cy.findByLabelText("Name").type(" alert"); + cy.findByRole("button", { name: "Save" }).click(); + }); + + cy.wait("@card"); + + modal().within(() => { + cy.findByRole("button", { name: "Set up an alert" }).click(); + }); + cy.findByRole("button", { name: "Done" }).click(); + + cy.wait("@savedAlert").then(({ response: { body } }) => { + expect(body.channels[0].channel_type).to.eq("email"); + expect(body.channels[0].enabled).to.eq(true); + }); + }); }); function openAlertForQuestion(id = 1) { diff --git a/frontend/src/metabase/query_builder/components/AlertModals.jsx b/frontend/src/metabase/query_builder/components/AlertModals.jsx index 333a9eaa5405802ac98060e9700586c8669b5a03..0d8770e5835a92e53d9bbd3e4eda52e10abaeccd 100644 --- a/frontend/src/metabase/query_builder/components/AlertModals.jsx +++ b/frontend/src/metabase/query_builder/components/AlertModals.jsx @@ -84,7 +84,7 @@ class CreateAlertModalContentInner extends Component { this.setState({ alert: { ...this.state.alert, - card: { id: newProps.question.id() }, + card: { ...this.state.alert.card, id: newProps.question.id() }, }, }); } @@ -548,30 +548,26 @@ export const AlertSettingToggle = ({ </div> ); -export class AlertEditSchedule extends Component { - render() { - const { alertType, schedule } = this.props; - - return ( - <div> - <h3 className="mt4 mb3 text-dark"> - How often should we check for results? - </h3> - - <div className="bordered rounded mb2"> - {alertType === ALERT_TYPE_ROWS && <RawDataAlertTip />} - <div className="p3 bg-light"> - <SchedulePicker - schedule={schedule} - scheduleOptions={["hourly", "daily", "weekly"]} - onScheduleChange={this.props.onScheduleChange} - textBeforeInterval="Check" - /> - </div> +export function AlertEditSchedule({ alertType, schedule, onScheduleChange }) { + return ( + <div> + <h3 className="mt4 mb3 text-dark"> + How often should we check for results? + </h3> + + <div className="bordered rounded mb2"> + {alertType === ALERT_TYPE_ROWS && <RawDataAlertTip />} + <div className="p3 bg-light"> + <SchedulePicker + schedule={schedule} + scheduleOptions={["hourly", "daily", "weekly"]} + onScheduleChange={onScheduleChange} + textBeforeInterval="Check" + /> </div> </div> - ); - } + </div> + ); } class AlertEditChannelsInner extends Component { @@ -632,33 +628,26 @@ export const AlertEditChannels = _.compose( ), )(AlertEditChannelsInner); -// TODO: Not sure how to translate text with formatting properly -class RawDataAlertTipInner extends Component { - render() { - const display = this.props.question.display(); - const vizSettings = this.props.visualizationSettings; - const goalEnabled = vizSettings["graph.show_goal"]; - const isLineAreaBar = - display === "line" || display === "area" || display === "bar"; - const isMultiSeries = - isLineAreaBar && - vizSettings["graph.metrics"] && - vizSettings["graph.metrics"].length > 1; - const showMultiSeriesGoalAlert = goalEnabled && isMultiSeries; +function RawDataAlertTipInner(props) { + const display = props.question.display(); + const vizSettings = props.visualizationSettings; + const goalEnabled = vizSettings["graph.show_goal"]; + const isLineAreaBar = + display === "line" || display === "area" || display === "bar"; + const isMultiSeries = + isLineAreaBar && + vizSettings["graph.metrics"] && + vizSettings["graph.metrics"].length > 1; + const showMultiSeriesGoalAlert = goalEnabled && isMultiSeries; - return ( - <div className="border-row-divider p3 flex align-center"> - <div className="circle flex align-center justify-center bg-light p2 mr2 text-medium"> - <Icon name="lightbulb" size="20" /> - </div> - {showMultiSeriesGoalAlert ? ( - <MultiSeriesAlertTip /> - ) : ( - <NormalAlertTip /> - )} + return ( + <div className="border-row-divider p3 flex align-center"> + <div className="circle flex align-center justify-center bg-light p2 mr2 text-medium"> + <Icon name="lightbulb" size="20" /> </div> - ); - } + {showMultiSeriesGoalAlert ? <MultiSeriesAlertTip /> : <NormalAlertTip />} + </div> + ); } export const RawDataAlertTip = connect(state => ({ @@ -675,8 +664,8 @@ export const MultiSeriesAlertTip = () => ( ); export const NormalAlertTip = () => ( <div>{jt`${( - <strong>{t`Tip`}:</strong> + <strong key="alert-tip">{t`Tip`}:</strong> )} This kind of alert is most useful when your saved question doesn’t ${( - <em>{t`usually`}</em> + <em key="alert-tip-em">{t`usually`}</em> )} return any results, but you want to know when it does.`}</div> );