From e8d1a6040bbd5d3d37d24ce8e5428a216a26669a Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Mon, 6 Dec 2021 19:57:42 +0300
Subject: [PATCH] Remove flow from containers (#19210)

---
 .../containers/AdHocQuestionLoader.jsx        |  33 +-----
 .../containers/AddToDashSelectDashModal.jsx   |  10 --
 .../containers/CandidateListLoader.jsx        |  27 +----
 .../containers/CollectionItemsLoader.jsx      |   8 +-
 frontend/src/metabase/containers/Form.jsx     | 109 ++----------------
 .../containers/QuestionAndResultLoader.jsx    |  18 +--
 .../metabase/containers/QuestionLoader.jsx    |  17 +--
 .../containers/QuestionResultLoader.jsx       |  37 +-----
 .../containers/SavedQuestionLoader.jsx        |  35 +-----
 9 files changed, 31 insertions(+), 263 deletions(-)

diff --git a/frontend/src/metabase/containers/AdHocQuestionLoader.jsx b/frontend/src/metabase/containers/AdHocQuestionLoader.jsx
index 29e8ae47598..0517c0df769 100644
--- a/frontend/src/metabase/containers/AdHocQuestionLoader.jsx
+++ b/frontend/src/metabase/containers/AdHocQuestionLoader.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/prop-types */
 import React from "react";
 import { connect } from "react-redux";
 
@@ -9,30 +10,6 @@ import { getMetadata } from "metabase/selectors/metadata";
 import Question from "metabase-lib/lib/Question";
 
 // type annotations
-import type Metadata from "metabase-lib/lib/metadata/Metadata";
-import type { Card } from "metabase-types/types/Card";
-
-type ChildProps = {
-  loading: boolean,
-  error: ?any,
-  question: ?Question,
-};
-
-type Props = {
-  questionHash?: string,
-  children?: (props: ChildProps) => React.Element,
-  // provided by redux
-  loadMetadataForCard: (card: Card) => Promise<void>,
-  metadata: Metadata,
-};
-
-type State = {
-  // the question should be of type Question if it is set
-  question: ?Question,
-  card: ?Card,
-  loading: boolean,
-  error: ?any,
-};
 
 /*
  * AdHocQuestionLoader
@@ -64,9 +41,7 @@ type State = {
  * without the redux store.
  */
 export class AdHocQuestionLoader extends React.Component {
-  props: Props;
-
-  state: State = {
+  state = {
     // this will store the loaded question
     question: null,
     // keep a reference to the card as well to help with re-creating question
@@ -81,7 +56,7 @@ export class AdHocQuestionLoader extends React.Component {
     this._loadQuestion(this.props.questionHash);
   }
 
-  UNSAFE_componentWillReceiveProps(nextProps: Props) {
+  UNSAFE_componentWillReceiveProps(nextProps) {
     // if the questionHash changes (this will most likely be the result of a
     // url change) then we need to load this new question
     if (nextProps.questionHash !== this.props.questionHash) {
@@ -106,7 +81,7 @@ export class AdHocQuestionLoader extends React.Component {
    *    be used
    * 4. Set the component state to the new Question
    */
-  async _loadQuestion(questionHash: ?string) {
+  async _loadQuestion(questionHash) {
     if (!questionHash) {
       this.setState({
         loading: false,
diff --git a/frontend/src/metabase/containers/AddToDashSelectDashModal.jsx b/frontend/src/metabase/containers/AddToDashSelectDashModal.jsx
index 4c6cf8c0ec0..bfd96102af7 100644
--- a/frontend/src/metabase/containers/AddToDashSelectDashModal.jsx
+++ b/frontend/src/metabase/containers/AddToDashSelectDashModal.jsx
@@ -12,9 +12,6 @@ import DashboardPicker from "metabase/containers/DashboardPicker";
 
 import * as Urls from "metabase/lib/urls";
 
-import type { Dashboard as DashboardType } from "metabase-types/types/Dashboard";
-import type { Card } from "metabase-types/types/Card";
-
 function mapStateToProps(state) {
   return {
     dashboards: state.entities.dashboards,
@@ -27,13 +24,6 @@ export default class AddToDashSelectDashModal extends Component {
     shouldCreateDashboard: false,
   };
 
-  props: {
-    card: Card,
-    onClose: () => void,
-    onChangeLocation: string => void,
-    createDashboard: DashboardType => any,
-  };
-
   navigateToDashboard = dashboard => {
     const { card, onChangeLocation } = this.props;
 
diff --git a/frontend/src/metabase/containers/CandidateListLoader.jsx b/frontend/src/metabase/containers/CandidateListLoader.jsx
index 778de0405ca..8bb188d8bda 100644
--- a/frontend/src/metabase/containers/CandidateListLoader.jsx
+++ b/frontend/src/metabase/containers/CandidateListLoader.jsx
@@ -1,45 +1,22 @@
+/* eslint-disable react/prop-types */
 import React from "react";
 import _ from "underscore";
 
 import { MetabaseApi, AutoApi } from "metabase/services";
 
-import type { DatabaseCandidates } from "metabase-types/types/Auto";
-
-type Props = {
-  databaseId: number,
-  children: (props: RenderProps) => ?React.Element,
-};
-
-type RenderProps = {
-  candidates: ?DatabaseCandidates,
-  sampleCandidates: ?DatabaseCandidates,
-  isSample: ?boolean,
-};
-
-type State = {
-  databaseId: ?number,
-  isSample: ?boolean,
-  candidates: ?DatabaseCandidates,
-  sampleCandidates: ?DatabaseCandidates,
-};
-
 const CANDIDATES_POLL_INTERVAL = 2000;
 // ensure this is 1 second offset from CANDIDATES_POLL_INTERVAL due to
 // concurrency issue in candidates endpoint
 const CANDIDATES_TIMEOUT = 11000;
 
 class CandidateListLoader extends React.Component {
-  props: Props;
-  state: State = {
+  state = {
     databaseId: null,
     isSample: null,
     candidates: null,
     sampleCandidates: null,
   };
 
-  _sampleTimeout: ?number;
-  _pollTimer: ?number;
-
   async UNSAFE_componentWillMount() {
     // If we get passed in a database id, just use that.
     // Don't fall back to the sample dataset
diff --git a/frontend/src/metabase/containers/CollectionItemsLoader.jsx b/frontend/src/metabase/containers/CollectionItemsLoader.jsx
index 8f6a2010462..e0b64dfb376 100644
--- a/frontend/src/metabase/containers/CollectionItemsLoader.jsx
+++ b/frontend/src/metabase/containers/CollectionItemsLoader.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/prop-types */
 import React from "react";
 
 import Collection from "metabase/entities/collections";
@@ -5,12 +6,7 @@ import Search from "metabase/entities/search";
 
 const PINNED_DASHBOARDS_LOAD_LIMIT = 500;
 
-type Props = {
-  collectionId: number,
-  children: () => void,
-};
-
-const CollectionItemsLoader = ({ collectionId, children, ...props }: Props) => (
+const CollectionItemsLoader = ({ collectionId, children, ...props }) => (
   <Collection.Loader {...props} id={collectionId}>
     {({ object }) => (
       <Search.ListLoader
diff --git a/frontend/src/metabase/containers/Form.jsx b/frontend/src/metabase/containers/Form.jsx
index 731c0e00532..e0061655283 100644
--- a/frontend/src/metabase/containers/Form.jsx
+++ b/frontend/src/metabase/containers/Form.jsx
@@ -20,78 +20,6 @@ export {
   CustomFormSection as FormSection,
 } from "metabase/components/form/CustomForm";
 
-type FormFieldName = string;
-type FormFieldTitle = string;
-type FormFieldDescription = string;
-type FormFieldType =
-  | "input"
-  | "password"
-  | "select"
-  | "text"
-  | "color"
-  | "hidden"
-  | "collection"
-  | "snippetCollection";
-
-type FormValue = any;
-type FormError = string;
-type FormValues = { [name: FormFieldName]: FormValue };
-type FormErrors = { [name: FormFieldName]: FormError };
-
-export type FormFieldDefinition = {
-  name: FormFieldName,
-  type?: FormFieldType,
-  title?: FormFieldTitle,
-  description?: FormFieldDescription,
-  initial?: FormValue | (() => FormValue),
-  normalize?: (value: FormValue) => FormValue,
-  validate?: (value: FormValue, props: FormProps) => ?FormError | boolean,
-  readOnly?: boolean,
-};
-
-export type FormDefinition = {
-  fields:
-    | ((values: FormValues) => FormFieldDefinition[])
-    | FormFieldDefinition[],
-  initial?: FormValues | (() => FormValues),
-  normalize?: (values: FormValues) => FormValues,
-  validate?: (values: FormValues, props: FormProps) => FormErrors,
-};
-
-type FormObject = {
-  fields: (values: FormValues) => FormFieldDefinition[],
-  fieldNames: (values: FormValues) => FormFieldName[],
-  initial: () => FormValues,
-  normalize: (values: FormValues) => FormValues,
-  validate: (values: FormValues, props: FormProps) => FormErrors,
-  disablePristineSubmit?: boolean,
-};
-
-type FormProps = {
-  values?: FormValues,
-};
-
-type Props = {
-  form: FormDefinition,
-  initialValues?: ?FormValues,
-  formName?: string,
-  onSubmit: (values: FormValues) => Promise<any>,
-  onSubmitSuccess: (action: any) => Promise<any>,
-  formComponent?: React.Component,
-  dispatch: Function,
-  values: FormValues,
-};
-
-type State = {
-  inlineFields: { [name: FormFieldName]: FormFieldDefinition },
-};
-
-type SubmitState = {
-  submitting: boolean,
-  failed: boolean,
-  result: any,
-};
-
 let FORM_ID = 0;
 // use makeMapStateToProps so each component gets it's own unique formId
 const makeMapStateToProps = () => {
@@ -128,21 +56,13 @@ const ReduxFormComponent = reduxForm()(
 
 @connect(makeMapStateToProps)
 export default class Form extends React.Component {
-  props: Props;
-  state: State;
-
-  _state: SubmitState = {
+  _state = {
     submitting: false,
     failed: false,
     result: undefined,
   };
 
-  _getFormDefinition: () => FormDefinition;
-  _getFormObject: () => FormObject;
-  _getInitialValues: () => FormValues;
-  _getFieldNames: () => FormFieldName[];
-
-  constructor(props: Props) {
+  constructor(props) {
     super(props);
 
     this.state = {
@@ -239,7 +159,7 @@ export default class Form extends React.Component {
     fieldNames: PropTypes.array,
   };
 
-  componentDidUpdate(prevProps: Props, prevState: State) {
+  componentDidUpdate(prevProps, prevState) {
     // HACK: when new fields are added they aren't initialized with their intialValues, so we have to force it here:
     const newFields = _.difference(
       Object.keys(this.state.inlineFields),
@@ -252,7 +172,7 @@ export default class Form extends React.Component {
     }
   }
 
-  _registerFormField = (field: FormFieldDefinition) => {
+  _registerFormField = field => {
     if (!_.isEqual(this.state.inlineFields[field.name], field)) {
       this.setState(prevState =>
         assocIn(prevState, ["inlineFields", field.name], field),
@@ -260,7 +180,7 @@ export default class Form extends React.Component {
     }
   };
 
-  _unregisterFormField = (field: FormFieldDefinition) => {
+  _unregisterFormField = field => {
     if (this.state.inlineFields[field.name]) {
       // this.setState(prevState =>
       //   dissocIn(prevState, ["inlineFields", field.name]),
@@ -275,7 +195,7 @@ export default class Form extends React.Component {
     };
   }
 
-  _validate = (values: FormValues, props: any) => {
+  _validate = (values, props) => {
     // HACK: clears failed state for global error
     if (!this._state.submitting && this._state.failed) {
       this._state.failed = false;
@@ -285,7 +205,7 @@ export default class Form extends React.Component {
     return formObject.validate(values, props);
   };
 
-  _onSubmit = async (values: FormValues) => {
+  _onSubmit = async values => {
     const formObject = this._getFormObject();
     // HACK: clears failed state for global error
     this._state.submitting = true;
@@ -320,7 +240,7 @@ export default class Form extends React.Component {
     }
   };
 
-  _handleSubmitSuccess = async (action: any) => {
+  _handleSubmitSuccess = async action => {
     if (this.props.onSubmitSuccess) {
       await this.props.onSubmitSuccess(action);
     }
@@ -329,7 +249,7 @@ export default class Form extends React.Component {
     );
   };
 
-  _handleChangeField = (fieldName: FormFieldName, value: FormValue) => {
+  _handleChangeField = (fieldName, value) => {
     return this.props.dispatch(change(this.props.formName, fieldName, value));
   };
 
@@ -370,12 +290,7 @@ export default class Form extends React.Component {
 // form.fields[0] is { name: "foo", initial: "bar" }
 // form.fields[0] is { name: "foo", initial: () => "bar" }
 //
-function makeFormMethod(
-  form: FormObject,
-  methodName: string,
-  defaultValues: any = {},
-  mergeFn,
-) {
+function makeFormMethod(form, methodName, defaultValues = {}, mergeFn) {
   const originalMethod = form[methodName];
   form[methodName] = (object, ...args) => {
     // make a copy
@@ -397,10 +312,10 @@ function makeFormMethod(
   };
 }
 // if the first arg is a function, call it, otherwise return it.
-function getValue(fnOrValue, ...args): any {
+function getValue(fnOrValue, ...args) {
   return typeof fnOrValue === "function" ? fnOrValue(...args) : fnOrValue;
 }
-function makeFormObject(formDef: FormDefinition): FormObject {
+function makeFormObject(formDef) {
   const form = {
     ...formDef,
     fields: values => getValue(formDef.fields, values),
diff --git a/frontend/src/metabase/containers/QuestionAndResultLoader.jsx b/frontend/src/metabase/containers/QuestionAndResultLoader.jsx
index c6fc8a6d7af..7fe65d2085e 100644
--- a/frontend/src/metabase/containers/QuestionAndResultLoader.jsx
+++ b/frontend/src/metabase/containers/QuestionAndResultLoader.jsx
@@ -1,19 +1,9 @@
+/* eslint-disable react/prop-types */
 import React from "react";
 
 import QuestionLoader from "metabase/containers/QuestionLoader";
 import QuestionResultLoader from "metabase/containers/QuestionResultLoader";
 
-import type { ChildProps as QuestionLoaderChildProps } from "./QuestionLoader";
-import type { ChildProps as QuestionResultLoaderChildProps } from "./QuestionResultLoader";
-
-type ChildProps = QuestionLoaderChildProps & QuestionResultLoaderChildProps;
-
-type Props = {
-  questionId?: ?number,
-  questionHash?: ?string,
-  children?: (props: ChildProps) => React.Element,
-};
-
 /*
  * QuestionAndResultLoader
  *
@@ -32,11 +22,7 @@ type Props = {
  * </QuestionAndResultLoader>
  *
  */
-const QuestionAndResultLoader = ({
-  questionId,
-  questionHash,
-  children,
-}: Props) => (
+const QuestionAndResultLoader = ({ questionId, questionHash, children }) => (
   <QuestionLoader questionId={questionId} questionHash={questionHash}>
     {({ loading: questionLoading, error: questionError, ...questionProps }) => (
       <QuestionResultLoader question={questionProps.question}>
diff --git a/frontend/src/metabase/containers/QuestionLoader.jsx b/frontend/src/metabase/containers/QuestionLoader.jsx
index b1b045ffc50..7e15ee4d009 100644
--- a/frontend/src/metabase/containers/QuestionLoader.jsx
+++ b/frontend/src/metabase/containers/QuestionLoader.jsx
@@ -1,25 +1,12 @@
+/* eslint-disable react/prop-types */
 import React from "react";
 import renderPropToHOC from "metabase/hoc/RenderPropToHOC";
 
 import AdHocQuestionLoader from "metabase/containers/AdHocQuestionLoader";
 import SavedQuestionLoader from "metabase/containers/SavedQuestionLoader";
 
-import Question from "metabase-lib/lib/Question";
 import { serializeCardForUrl } from "metabase/lib/card";
 
-export type ChildProps = {
-  loading: boolean,
-  error: ?any,
-  question: ?Question,
-};
-
-type Props = {
-  questionObject?: any, // FIXME: minimal card
-  questionId?: ?number,
-  questionHash?: ?string,
-  children?: (props: ChildProps) => React.Element,
-};
-
 /*
  * QuestionLoader
  *
@@ -62,7 +49,7 @@ const QuestionLoader = ({
   questionId,
   questionHash,
   children,
-}: Props) =>
+}) =>
   questionObject != null ? (
     <AdHocQuestionLoader questionHash={serializeCardForUrl(questionObject)}>
       {children}
diff --git a/frontend/src/metabase/containers/QuestionResultLoader.jsx b/frontend/src/metabase/containers/QuestionResultLoader.jsx
index 943a0ea7894..459ef8d87d3 100644
--- a/frontend/src/metabase/containers/QuestionResultLoader.jsx
+++ b/frontend/src/metabase/containers/QuestionResultLoader.jsx
@@ -1,36 +1,8 @@
+/* eslint-disable react/prop-types */
 import React from "react";
 import PropTypes from "prop-types";
 import { defer } from "metabase/lib/promise";
 
-import type { Dataset } from "metabase-types/types/Dataset";
-import type { RawSeries } from "metabase-types/types/Visualization";
-
-import Question from "metabase-lib/lib/Question";
-
-export type ChildProps = {
-  loading: boolean,
-  error: ?any,
-  results: ?(Dataset[]),
-  result: ?Dataset,
-  rawSeries: ?RawSeries,
-  cancel: () => void,
-  reload: () => void,
-};
-
-type OnLoadCallback = (results: ?(Dataset[])) => void;
-
-type Props = {
-  question: ?Question,
-  children?: (props: ChildProps) => React.Element,
-  onLoad?: OnLoadCallback,
-};
-
-type State = {
-  results: ?(Dataset[]),
-  loading: boolean,
-  error: ?any,
-};
-
 const propTypes = {
   question: PropTypes.object,
   children: PropTypes.func,
@@ -57,15 +29,12 @@ const propTypes = {
  *
  */
 export class QuestionResultLoader extends React.Component {
-  props: Props;
-  state: State = {
+  state = {
     results: null,
     loading: false,
     error: null,
   };
 
-  _cancelDeferred: ?() => void;
-
   UNSAFE_componentWillMount = () => {
     this._reload();
   };
@@ -96,7 +65,7 @@ export class QuestionResultLoader extends React.Component {
         }));
 
         // call apiGetResults and pass our cancel to allow for cancelation
-        const results: Dataset[] = await question.apiGetResults({
+        const results = await question.apiGetResults({
           cancelDeferred: this._cancelDeferred,
         });
 
diff --git a/frontend/src/metabase/containers/SavedQuestionLoader.jsx b/frontend/src/metabase/containers/SavedQuestionLoader.jsx
index c9a1b415b87..4ec739c4d12 100644
--- a/frontend/src/metabase/containers/SavedQuestionLoader.jsx
+++ b/frontend/src/metabase/containers/SavedQuestionLoader.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/prop-types */
 import React from "react";
 import { connect } from "react-redux";
 
@@ -9,32 +10,6 @@ import { getMetadata } from "metabase/selectors/metadata";
 import Question from "metabase-lib/lib/Question";
 
 // type annotations
-import type Metadata from "metabase-lib/lib/metadata/Metadata";
-import type { Card } from "metabase-types/types/Card";
-
-type ChildProps = {
-  loading: boolean,
-  error: ?any,
-  question: ?Question,
-};
-
-type Props = {
-  questionId: ?number,
-  children?: (props: ChildProps) => React.Element,
-  // provided by redux
-  loadMetadataForCard: (card: Card) => Promise<void>,
-  metadata: Metadata,
-};
-
-type State = {
-  // the question should be of type Question if it is set
-  question: ?Question,
-  // keep a reference to the card as well to help with re-creating question
-  // objects if the underlying metadata changes
-  card: ?Card,
-  loading: boolean,
-  error: ?any,
-};
 
 /*
  * SavedQuestionLaoder
@@ -65,9 +40,7 @@ type State = {
  * without the redux store.
  */
 export class SavedQuestionLoader extends React.Component {
-  props: Props;
-
-  state: State = {
+  state = {
     // this will store the loaded question
     question: null,
     card: null,
@@ -80,7 +53,7 @@ export class SavedQuestionLoader extends React.Component {
     this._loadQuestion(this.props.questionId);
   }
 
-  UNSAFE_componentWillReceiveProps(nextProps: Props) {
+  UNSAFE_componentWillReceiveProps(nextProps) {
     // if the questionId changes (this will most likely be the result of a
     // url change) then we need to load this new question
     if (nextProps.questionId !== this.props.questionId) {
@@ -105,7 +78,7 @@ export class SavedQuestionLoader extends React.Component {
    *    be used
    * 4. Set the component state to the new Question
    */
-  async _loadQuestion(questionId: ?number) {
+  async _loadQuestion(questionId) {
     if (questionId == null) {
       this.setState({
         loading: false,
-- 
GitLab