<commit_before>import { isFunction } from "lodash";
import React from "react";
import PropTypes from "prop-types";
import debug from "debug";
import Alert from "antd/lib/alert";

const logger = debug("redash:errors");

export const ErrorBoundaryContext = React.createContext({
  handleError: error => {
    // Allow calling chain to roll up, and then throw the error in global context
    setTimeout(() => {
      throw error;
    });
  },
  reset: () => {},
});

export function ErrorMessage({ children }) {
  return <Alert message={children} type="error" showIcon />;
}

ErrorMessage.propTypes = {
  children: PropTypes.node,
};

ErrorMessage.defaultProps = {
  children: "Something went wrong.",
};

export default class ErrorBoundary extends React.Component {
  static propTypes = {
    children: PropTypes.node,
    renderError: PropTypes.func, // error => ReactNode
  };

  static defaultProps = {
    children: null,
    renderError: null,
  };

  state = { error: null };

  handleError = error => {
    this.setState(this.constructor.getDerivedStateFromError(error));
    this.componentDidCatch(error, null);
  };

  reset = () => {
    this.setState({ error: null });
  };

  static getDerivedStateFromError(error) {
    return { error };
  }

  componentDidCatch(error, errorInfo) {
    logger(error, errorInfo);
  }

  render() {<commit_msg>Handle React exception when a function is provided (#5016)<commit_after>import { isFunction } from "lodash";
import React from "react";
import PropTypes from "prop-types";
import debug from "debug";
import Alert from "antd/lib/alert";

const logger = debug("redash:errors");

export const ErrorBoundaryContext = React.createContext({
  handleError: error => {
    // Allow calling chain to roll up, and then throw the error in global context
    setTimeout(() => {
      throw error;
    });
  },
  reset: () => {},
});

export function ErrorMessage({ children }) {
  return <Alert message={children} type="error" showIcon />;
}

ErrorMessage.propTypes = {
  children: PropTypes.node,
};

ErrorMessage.defaultProps = {
  children: "Something went wrong.",
};

export default class ErrorBoundary extends React.Component {
  static propTypes = {
    children: PropTypes.node,
    renderError: PropTypes.func, // error => ReactNode
  };

  static defaultProps = {
    children: null,
    renderError: null,
  };

  state = { error: null };

  handleError = error => {
    this.setState(this.constructor.getDerivedStateFromError(error));
    this.componentDidCatch(error, null);
    if (isFunction(window.handleException)) {
      window.handleException(error);
    }
  };

  reset = () => {
    this.setState({ error: null });
  };

  static getDerivedStateFromError(error) {
    return { error };
  }

  componentDidCatch(error, errorInfo) {
    logger(error, errorInfo);
  }

  render() {
{'fraction_non_alphanumeric': 0.1316901408450704, 'fraction_numerical': 0.0014084507042253522, 'mean_word_length': 3.719269102990033, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5818644', 'n_tokens_mistral': 840, 'n_tokens_neox': 827, 'n_words': 221}