From 68c6d37374c2013bd3f9e3fccc81f21c90a6ec15 Mon Sep 17 00:00:00 2001 From: wilkie Date: Thu, 9 Apr 2026 01:03:08 -0400 Subject: [PATCH 1/6] Updates to TypeScript. --- .eslintrc.js | 30 ++- babel.config.json | 3 +- package.json | 10 +- src/{App.js => App.tsx} | 134 ++++++----- ...FeatureButton.jsx => AddFeatureButton.tsx} | 19 +- ...riptions.jsx => AnimationDescriptions.tsx} | 11 +- ...ropdown.jsx => ColumnDataTypeDropdown.tsx} | 23 +- ...rical.jsx => ColumnDetailsCategorical.tsx} | 12 +- ...merical.jsx => ColumnDetailsNumerical.tsx} | 12 +- ...olumnInspector.jsx => ColumnInspector.tsx} | 23 +- .../{CrossTab.jsx => CrossTab.tsx} | 14 +- .../{DataCard.jsx => DataCard.tsx} | 24 +- .../{DataDisplay.jsx => DataDisplay.tsx} | 13 +- .../{DataTable.jsx => DataTable.tsx} | 40 ++-- ...enerateResults.jsx => GenerateResults.tsx} | 19 +- .../{ModelCard.jsx => ModelCard.tsx} | 27 +-- src/UIComponents/{Predict.jsx => Predict.tsx} | 46 ++-- src/UIComponents/{Results.jsx => Results.tsx} | 17 +- ...{ResultsDetails.jsx => ResultsDetails.tsx} | 24 +- .../{ResultsTable.jsx => ResultsTable.tsx} | 27 +-- .../{ResultsToggle.jsx => ResultsToggle.tsx} | 19 +- .../{SaveModel.jsx => SaveModel.tsx} | 51 ++-- .../{ScatterPlot.jsx => ScatterPlot.tsx} | 19 +- ...lableContent.jsx => ScrollableContent.tsx} | 14 +- .../{SelectDataset.jsx => SelectDataset.tsx} | 31 ++- ...tLabelButton.jsx => SelectLabelButton.tsx} | 19 +- .../{Statement.jsx => Statement.tsx} | 47 ++-- .../{TrainModel.jsx => TrainModel.tsx} | 31 ++- ...nsWarning.jsx => UniqueOptionsWarning.tsx} | 13 +- src/UIComponents/shapes.js | 83 ------- src/assetPath.js | 5 - src/assetPath.ts | 5 + src/{constants.js => constants.ts} | 2 +- ...svReaderWrapper.js => csvReaderWrapper.ts} | 40 ++-- ...{datasetManifest.js => datasetManifest.ts} | 19 +- src/declarations.d.ts | 37 +++ src/helpers/{accuracy.js => accuracy.ts} | 42 ++-- .../{columnDetails.js => columnDetails.ts} | 50 ++-- .../{datasetDetails.js => datasetDetails.ts} | 13 +- src/helpers/{metrics.js => metrics.ts} | 8 +- ...nValidation.js => navigationValidation.ts} | 41 ++-- src/helpers/{utils.js => utils.ts} | 10 +- ...{valueConversion.js => valueConversion.ts} | 20 +- src/{i18n.js => i18n.ts} | 14 +- src/{index.js => index.tsx} | 31 ++- src/{indexDev.js => indexDev.tsx} | 25 +- src/{indexProd.js => indexProd.tsx} | 0 ...nReaderWrapper.js => jsonReaderWrapper.ts} | 12 +- src/{redux.js => redux.ts} | 182 ++++++++------ src/{selectors.js => selectors.ts} | 40 ++-- ...Selectors.js => currentColumnSelectors.ts} | 108 ++++----- ...Selectors.js => visualizationSelectors.ts} | 77 +++--- src/{train.js => train.ts} | 52 ++-- src/trainers/{KNNTrainer.js => KNNTrainer.ts} | 43 ++-- src/types.ts | 104 ++++++++ test/unit/accuracy.test.js | 4 +- test/unit/columnDetails.test.js | 4 +- test/unit/currentColumnSelectors.test.js | 2 +- test/unit/navigationValidation.test.js | 2 +- test/unit/train.test.js | 4 +- test/unit/utils.test.js | 2 +- tsconfig.json | 21 ++ webpack.config.js | 10 +- yarn.lock | 226 +++++++++++++++++- 64 files changed, 1252 insertions(+), 858 deletions(-) rename src/{App.js => App.tsx} (75%) rename src/UIComponents/{AddFeatureButton.jsx => AddFeatureButton.tsx} (66%) rename src/UIComponents/{AnimationDescriptions.jsx => AnimationDescriptions.tsx} (83%) rename src/UIComponents/{ColumnDataTypeDropdown.jsx => ColumnDataTypeDropdown.tsx} (67%) rename src/UIComponents/{ColumnDetailsCategorical.jsx => ColumnDetailsCategorical.tsx} (88%) rename src/UIComponents/{ColumnDetailsNumerical.jsx => ColumnDetailsNumerical.tsx} (82%) rename src/UIComponents/{ColumnInspector.jsx => ColumnInspector.tsx} (90%) rename src/UIComponents/{CrossTab.jsx => CrossTab.tsx} (95%) rename src/UIComponents/{DataCard.jsx => DataCard.tsx} (89%) rename src/UIComponents/{DataDisplay.jsx => DataDisplay.tsx} (86%) rename src/UIComponents/{DataTable.jsx => DataTable.tsx} (89%) rename src/UIComponents/{GenerateResults.jsx => GenerateResults.tsx} (95%) rename src/UIComponents/{ModelCard.jsx => ModelCard.tsx} (92%) rename src/UIComponents/{Predict.jsx => Predict.tsx} (84%) rename src/UIComponents/{Results.jsx => Results.tsx} (93%) rename src/UIComponents/{ResultsDetails.jsx => ResultsDetails.tsx} (82%) rename src/UIComponents/{ResultsTable.jsx => ResultsTable.tsx} (92%) rename src/UIComponents/{ResultsToggle.jsx => ResultsToggle.tsx} (84%) rename src/UIComponents/{SaveModel.jsx => SaveModel.tsx} (88%) rename src/UIComponents/{ScatterPlot.jsx => ScatterPlot.tsx} (87%) rename src/UIComponents/{ScrollableContent.jsx => ScrollableContent.tsx} (54%) rename src/UIComponents/{SelectDataset.jsx => SelectDataset.tsx} (89%) rename src/UIComponents/{SelectLabelButton.jsx => SelectLabelButton.tsx} (66%) rename src/UIComponents/{Statement.jsx => Statement.tsx} (86%) rename src/UIComponents/{TrainModel.jsx => TrainModel.tsx} (91%) rename src/UIComponents/{UniqueOptionsWarning.jsx => UniqueOptionsWarning.tsx} (79%) delete mode 100644 src/UIComponents/shapes.js delete mode 100644 src/assetPath.js create mode 100644 src/assetPath.ts rename src/{constants.js => constants.ts} (99%) rename src/{csvReaderWrapper.js => csvReaderWrapper.ts} (59%) rename src/{datasetManifest.js => datasetManifest.ts} (73%) create mode 100644 src/declarations.d.ts rename src/helpers/{accuracy.js => accuracy.ts} (78%) rename src/helpers/{columnDetails.js => columnDetails.ts} (64%) rename src/helpers/{datasetDetails.js => datasetDetails.ts} (81%) rename src/helpers/{metrics.js => metrics.ts} (77%) rename src/helpers/{navigationValidation.js => navigationValidation.ts} (83%) rename src/helpers/{utils.js => utils.ts} (53%) rename src/helpers/{valueConversion.js => valueConversion.ts} (68%) rename src/{i18n.js => i18n.ts} (83%) rename src/{index.js => index.tsx} (75%) rename src/{indexDev.js => indexDev.tsx} (79%) rename src/{indexProd.js => indexProd.tsx} (100%) rename src/{jsonReaderWrapper.js => jsonReaderWrapper.ts} (75%) rename src/{redux.js => redux.ts} (74%) rename src/{selectors.js => selectors.ts} (59%) rename src/selectors/{currentColumnSelectors.js => currentColumnSelectors.ts} (53%) rename src/selectors/{visualizationSelectors.js => visualizationSelectors.ts} (69%) rename src/{train.js => train.ts} (72%) rename src/trainers/{KNNTrainer.js => KNNTrainer.ts} (78%) create mode 100644 src/types.ts create mode 100644 tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index 8b42a5f9..d00f8866 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,12 +6,14 @@ module.exports = { "globals": { }, "plugins": [ + "@typescript-eslint", "jsx-a11y", "react-hooks" ], "extends": [ 'plugin:react/recommended', "eslint:recommended", + "plugin:@typescript-eslint/recommended", "plugin:jsx-a11y/recommended", "plugin:react-hooks/recommended" ], @@ -25,7 +27,7 @@ module.exports = { "version": "detect" } }, - "parser": "@babel/eslint-parser", + "parser": "@typescript-eslint/parser", "parserOptions": { "sourceType": "module", "ecmaFeatures": { @@ -40,9 +42,10 @@ module.exports = { "dot-location": ["error", "property"], "eol-last": "error", eqeqeq: "error", - "jsx-quotes": "error", // autofixable + "jsx-quotes": "error", "keyword-spacing": "error", - "no-array-constructor": "error", + "no-array-constructor": "off", + "@typescript-eslint/no-array-constructor": "error", "no-console": "off", "no-duplicate-imports": "error", "no-empty": "off", @@ -52,31 +55,34 @@ module.exports = { "no-implicit-globals": "error", "no-new-object": "error", "no-trailing-spaces": "error", - "no-undef": "error", - "no-unused-vars": ["error", { args: "none" }], + "no-undef": "off", + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { args: "none" }], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-require-imports": "off", "no-useless-escape": "off", "no-with": "error", "object-curly-spacing": "off", "react/react-in-jsx-scope": "off", "react/button-has-type": "error", "react/display-name": "off", - "react/jsx-closing-bracket-location": "error", // autofixable - "react/jsx-curly-spacing": "error", // autofixable + "react/jsx-closing-bracket-location": "error", + "react/jsx-curly-spacing": "error", "react/jsx-first-prop-new-line": ["error", "multiline"], - "react/jsx-indent-props": ["error", 2], // autofixable + "react/jsx-indent-props": ["error", 2], "react/jsx-key": "off", "react/jsx-no-target-blank": "off", - "react/jsx-wrap-multilines": "error", // autofixable + "react/jsx-wrap-multilines": "error", "react/no-danger": "error", "react/no-find-dom-node": "off", "react/no-render-return-value": "off", "react/no-string-refs": "off", "react/no-unescaped-entities": "off", + "react/prop-types": "off", "react/self-closing-comp": "error", - semi: "off", // enforced by babel/semi + semi: "off", "space-before-blocks": "error", - strict: "error", + strict: "off", "jsx-a11y/no-onchange": 0 - } }; diff --git a/babel.config.json b/babel.config.json index fcde8385..1e588588 100644 --- a/babel.config.json +++ b/babel.config.json @@ -1,6 +1,7 @@ { "presets": [ ["@babel/preset-env", {"loose": true}], - ["@babel/preset-react", {"runtime": "automatic"}] + ["@babel/preset-react", {"runtime": "automatic"}], + "@babel/preset-typescript" ] } diff --git a/package.json b/package.json index e2b84902..9b44cc30 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "url": "git+ssh://git@github.com/code-dot-org/ml-playground.git" }, "jest": { + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json"], "moduleNameMapper": { ".+\\.(bin|jpg|jpeg|png|mp3|ogg|wav|gif)$": "identity-obj-proxy", "^@public(.*)$": "/public/$1" @@ -23,7 +24,7 @@ "build": "webpack --mode production", "start": "yarn run dev", "dev": "webpack-dev-server --mode development --static public --host 0.0.0.0 --allowed-hosts all", - "lint": "eslint --ext .js,.jsx src", + "lint": "eslint --ext .ts,.tsx src", "test": "yarn run lint && jest", "test:unit": "jest ./test/unit/*.js", "preversion": "yarn install && yarn run test", @@ -35,6 +36,11 @@ "@babel/eslint-parser": "^7.28.6", "@babel/preset-env": "^7.29.2", "@babel/preset-react": "^7.28.5", + "@babel/preset-typescript": "^7.28.5", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@typescript-eslint/eslint-plugin": "^8.58.1", + "@typescript-eslint/parser": "^8.58.1", "babel-jest": "29", "babel-loader": "^10.1.1", "copy-webpack-plugin": "11", @@ -55,6 +61,8 @@ "react-redux": "9", "redux": "^4.0.5", "style-loader": "^4.0.0", + "ts-loader": "^9.5.7", + "typescript": "^6.0.2", "webpack": "5", "webpack-bundle-analyzer": "^3.6.0", "webpack-cli": "5", diff --git a/src/App.js b/src/App.tsx similarity index 75% rename from src/App.js rename to src/App.tsx index 95ece78f..8ebcb132 100644 --- a/src/App.js +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import PropTypes from "prop-types"; +import React from "react"; import SelectDataset from "./UIComponents/SelectDataset"; import DataDisplay from "./UIComponents/DataDisplay"; import ColumnInspector from "./UIComponents/ColumnInspector"; @@ -24,6 +24,19 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSpinner } from "@fortawesome/free-solid-svg-icons"; import I18n from "./i18n"; +interface PanelButtonsProps { + panelButtons: any; + currentPanel: string; + setCurrentPanel: (panel: string) => void; + onContinue: () => void; + startSaveTrainedModel: (dataToSave: any) => void; + dataToSave: any; + saveStatus: string; + saveResponseData: any; + isSaveComplete: (saveStatus: string) => boolean; + shouldDisplaySaveStatus: (saveStatus: string) => boolean; +} + function PanelButtons({ panelButtons, currentPanel, @@ -35,7 +48,7 @@ function PanelButtons({ saveResponseData, isSaveComplete: isSaveCompleteProp, shouldDisplaySaveStatus: shouldDisplaySaveStatusProp -}) { +}: PanelButtonsProps) { const onClickPrev = () => { setCurrentPanel(panelButtons.prev.panel); }; @@ -50,11 +63,11 @@ function PanelButtons({ } }; - const localizedSaveMessage = saveStatus => { + const localizedSaveMessage = (saveStatus: string): string => { return I18n.t(`saveStatus_${saveStatus}`); }; - const saveResponseDataMessage = saveResponseData => { + const saveResponseDataMessage = (saveResponseData: any): string | undefined => { // The list of known error types from share_filtering.rb. const errorTypes = ["email", "address", "phone", "profanity"]; @@ -70,13 +83,13 @@ function PanelButtons({ } }; - let loadSaveStatus = isSaveCompleteProp(saveStatus) ? ( + const loadSaveStatus = isSaveCompleteProp(saveStatus) ? ( localizedSaveMessage(saveStatus) ) : ( ); - let loadSaveResponseData = isSaveCompleteProp(saveStatus) + const loadSaveResponseData = isSaveCompleteProp(saveStatus) ? saveResponseDataMessage(saveResponseData) : undefined; @@ -134,54 +147,57 @@ function PanelButtons({ ); } -PanelButtons.propTypes = { - panelButtons: PropTypes.object, - currentPanel: PropTypes.string, - setCurrentPanel: PropTypes.func, - onContinue: PropTypes.func, - startSaveTrainedModel: PropTypes.func, - dataToSave: PropTypes.object, - saveStatus: PropTypes.string, - saveResponseData: PropTypes.object, - isSaveComplete: PropTypes.func, - shouldDisplaySaveStatus: PropTypes.func -}; +interface BodyContainerProps { + children: React.ReactNode; +} -const BodyContainer = props => ( -
{props.children}
-); +function BodyContainer({ children }: BodyContainerProps) { + return
{children}
; +} -BodyContainer.propTypes = { - children: PropTypes.node -}; +interface ContainerLeftProps { + children: React.ReactNode; +} -const ContainerLeft = props => ( -
- {props.children} -
-); +function ContainerLeft({ children }: ContainerLeftProps) { + return ( +
+ {children} +
+ ); +} -ContainerLeft.propTypes = { - children: PropTypes.node -}; +interface ContainerRightProps { + children: React.ReactNode; +} -const ContainerRight = props => ( -
- {props.children} -
-); +function ContainerRight({ children }: ContainerRightProps) { + return ( +
+ {children} +
+ ); +} -ContainerRight.propTypes = { - children: PropTypes.node -}; +interface ContainerFullWidthProps { + children: React.ReactNode; +} -const ContainerFullWidth = props => ( -
{props.children}
-); +function ContainerFullWidth({ children }: ContainerFullWidthProps) { + return
{children}
; +} -ContainerFullWidth.propTypes = { - children: PropTypes.node -}; +interface AppProps { + panelButtons: any; + currentPanel: string; + setCurrentPanel: (panel: string) => void; + onContinue: () => void; + resultsPhase: number; + startSaveTrainedModel: (dataToSave: any) => void; + dataToSave: any; + saveStatus: string; + saveResponseData: any; +} function App({ panelButtons, @@ -193,7 +209,7 @@ function App({ dataToSave, saveStatus, saveResponseData -}) { +}: AppProps) { return (
{currentPanel === "selectDataset" && ( @@ -280,22 +296,8 @@ function App({ ); } -App.propTypes = { - panelButtons: PropTypes.object, - currentPanel: PropTypes.string, - setCurrentPanel: PropTypes.func, - onContinue: PropTypes.func, - resultsPhase: PropTypes.number, - startSaveTrainedModel: PropTypes.func, - dataToSave: PropTypes.object, - saveStatus: PropTypes.string, - saveResponseData: PropTypes.object, - isSaveComplete: PropTypes.func, - shouldDisplaySaveStatus: PropTypes.func -}; - export default connect( - state => ({ + (state: any) => ({ panelButtons: getPanelButtons(state), currentPanel: state.currentPanel, resultsPhase: state.resultsPhase, @@ -303,14 +305,14 @@ export default connect( saveStatus: state.saveStatus, saveResponseData: state.saveResponseData }), - dispatch => ({ - setCurrentPanel(panel) { + (dispatch: any) => ({ + setCurrentPanel(panel: string) { dispatch(setCurrentPanel(panel)); }, - isSaveComplete(state) { + isSaveComplete(state: any) { dispatch(isSaveComplete(state)); }, - shouldDisplaySaveStatus(state) { + shouldDisplaySaveStatus(state: any) { dispatch(shouldDisplaySaveStatus(state)); } }) diff --git a/src/UIComponents/AddFeatureButton.jsx b/src/UIComponents/AddFeatureButton.tsx similarity index 66% rename from src/UIComponents/AddFeatureButton.jsx rename to src/UIComponents/AddFeatureButton.tsx index cd0dc475..ffd09810 100644 --- a/src/UIComponents/AddFeatureButton.jsx +++ b/src/UIComponents/AddFeatureButton.tsx @@ -1,12 +1,16 @@ /* React component to handle selecting columns as features. */ -import PropTypes from "prop-types"; import { connect } from "react-redux"; import { styles } from "../constants"; import { addSelectedFeature } from "../redux"; import I18n from "../i18n"; -function AddFeatureButton({ column, addSelectedFeature }) { - const addFeature = (event, column) => { +interface AddFeatureButtonProps { + column?: string; + addSelectedFeature: (column: string) => void; +} + +function AddFeatureButton({ column, addSelectedFeature }: AddFeatureButtonProps) { + const addFeature = (event: React.MouseEvent, column: string) => { addSelectedFeature(column); event.preventDefault(); }; @@ -23,15 +27,10 @@ function AddFeatureButton({ column, addSelectedFeature }) { ); } -AddFeatureButton.propTypes = { - column: PropTypes.string, - addSelectedFeature: PropTypes.func.isRequired -}; - export default connect( - state => ({}), + (state: any) => ({}), dispatch => ({ - addSelectedFeature(column) { + addSelectedFeature(column: string) { dispatch(addSelectedFeature(column)); } }) diff --git a/src/UIComponents/AnimationDescriptions.jsx b/src/UIComponents/AnimationDescriptions.tsx similarity index 83% rename from src/UIComponents/AnimationDescriptions.jsx rename to src/UIComponents/AnimationDescriptions.tsx index 18fc2244..15a3d5a2 100644 --- a/src/UIComponents/AnimationDescriptions.jsx +++ b/src/UIComponents/AnimationDescriptions.tsx @@ -1,8 +1,11 @@ /* React component to handle animation descriptions for screen readers. */ -import PropTypes from "prop-types"; import I18n from "../i18n"; -function AnimationDescription({ description }) { +interface AnimationDescriptionProps { + description?: string; +} + +function AnimationDescription({ description }: AnimationDescriptionProps) { return (
@@ -16,10 +19,6 @@ function AnimationDescription({ description }) { ); } -AnimationDescription.propTypes = { - description: PropTypes.string -}; - function TrainingAnimationDescription() { return ( { +interface ColumnDataTypeDropdownProps { + columnId?: string; + currentDataType?: string; + setColumnsByDataType: (column: string, dataType: string) => void; +} + +function ColumnDataTypeDropdown({ columnId, currentDataType, setColumnsByDataType }: ColumnDataTypeDropdownProps) { + const handleChangeDataType = (event: React.ChangeEvent, feature: string) => { event.preventDefault(); setColumnsByDataType(feature, event.target.value); }; @@ -31,16 +36,10 @@ function ColumnDataTypeDropdown({ columnId, currentDataType, setColumnsByDataTyp ); } -ColumnDataTypeDropdown.propTypes = { - columnId: PropTypes.string, - currentDataType: PropTypes.oneOf(Object.values(ColumnTypes)), - setColumnsByDataType: PropTypes.func.isRequired -}; - export default connect( - state => ({}), + (state: any) => ({}), dispatch => ({ - setColumnsByDataType(column, dataType) { + setColumnsByDataType(column: string, dataType: string) { dispatch(setColumnsByDataType(column, dataType)); } }) diff --git a/src/UIComponents/ColumnDetailsCategorical.jsx b/src/UIComponents/ColumnDetailsCategorical.tsx similarity index 88% rename from src/UIComponents/ColumnDetailsCategorical.jsx rename to src/UIComponents/ColumnDetailsCategorical.tsx index b3721477..88b3fc4e 100644 --- a/src/UIComponents/ColumnDetailsCategorical.jsx +++ b/src/UIComponents/ColumnDetailsCategorical.tsx @@ -2,11 +2,15 @@ import { connect } from "react-redux"; import { colors, styles } from "../constants"; import { Bar } from "react-chartjs-2"; -import { categeoricalColumnDetailsShape } from "./shapes"; import { getCategoricalColumnDetails } from "../selectors/currentColumnSelectors"; import I18n from "../i18n"; +import { CategoricalColumnDetails } from "../types"; + +interface ColumnDetailsCategoricalProps { + columnDetails: CategoricalColumnDetails; +} const chartOptions = { scales: { @@ -22,7 +26,7 @@ const chartOptions = { maintainAspectRatio: false }; -function ColumnDetailsCategorical({ columnDetails }) { +function ColumnDetailsCategorical({ columnDetails }: ColumnDetailsCategoricalProps) { const { id, uniqueOptions, frequencies } = columnDetails; const labels = uniqueOptions && Object.values(uniqueOptions); const barData = { @@ -67,10 +71,6 @@ function ColumnDetailsCategorical({ columnDetails }) { ); } -ColumnDetailsCategorical.propTypes = { - columnDetails: categeoricalColumnDetailsShape -}; - export default connect( state => ({ columnDetails: getCategoricalColumnDetails(state) diff --git a/src/UIComponents/ColumnDetailsNumerical.jsx b/src/UIComponents/ColumnDetailsNumerical.tsx similarity index 82% rename from src/UIComponents/ColumnDetailsNumerical.jsx rename to src/UIComponents/ColumnDetailsNumerical.tsx index 3762294d..f6c9d855 100644 --- a/src/UIComponents/ColumnDetailsNumerical.jsx +++ b/src/UIComponents/ColumnDetailsNumerical.tsx @@ -2,10 +2,14 @@ import { connect } from "react-redux"; import { styles } from "../constants"; import { getNumericalColumnDetails } from "../selectors/currentColumnSelectors"; -import { numericalColumnDetailsShape } from "./shapes" import I18n from "../i18n"; +import { NumericalColumnDetails } from "../types"; -function ColumnDetailsNumerical({ columnDetails }) { +interface ColumnDetailsNumericalProps { + columnDetails: NumericalColumnDetails; +} + +function ColumnDetailsNumerical({ columnDetails }: ColumnDetailsNumericalProps) { const { extrema, containsOnlyNumbers } = columnDetails; return ( @@ -27,10 +31,6 @@ function ColumnDetailsNumerical({ columnDetails }) { ); } -ColumnDetailsNumerical.propTypes = { - columnDetails: numericalColumnDetailsShape -}; - export default connect( state => ({ columnDetails: getNumericalColumnDetails(state) diff --git a/src/UIComponents/ColumnInspector.jsx b/src/UIComponents/ColumnInspector.tsx similarity index 90% rename from src/UIComponents/ColumnInspector.jsx rename to src/UIComponents/ColumnInspector.tsx index f412c3b2..de9e54b5 100644 --- a/src/UIComponents/ColumnInspector.jsx +++ b/src/UIComponents/ColumnInspector.tsx @@ -2,10 +2,9 @@ React component to handle displaying details, including data visualizations, for selected columns. */ -import PropTypes from "prop-types"; import { connect } from "react-redux"; import { getCurrentColumnDetails } from "../selectors/currentColumnSelectors"; -import { styles, ColumnTypes } from "../constants.js"; +import { styles, ColumnTypes } from "../constants"; import ScatterPlot from "./ScatterPlot"; import CrossTab from "./CrossTab"; import ScrollableContent from "./ScrollableContent"; @@ -15,11 +14,17 @@ import ColumnDataTypeDropdown from "./ColumnDataTypeDropdown"; import AddFeatureButton from "./AddFeatureButton"; import SelectLabelButton from "./SelectLabelButton"; import UniqueOptionsWarning from "./UniqueOptionsWarning"; -import { currentColumnInspectorShape } from "./shapes"; import I18n from "../i18n"; -import { getLocalizedColumnName } from "../helpers/columnDetails.js"; +import { getLocalizedColumnName } from "../helpers/columnDetails"; +import { CurrentColumnInspector } from "../types"; -function ColumnInspector({ currentColumnDetails, currentPanel, datasetId }) { +interface ColumnInspectorProps { + currentColumnDetails: CurrentColumnInspector | undefined; + currentPanel: string; + datasetId: string; +} + +function ColumnInspector({ currentColumnDetails, currentPanel, datasetId }: ColumnInspectorProps) { const selectingFeatures = currentPanel === "dataDisplayFeatures"; const selectingLabel = currentPanel === "dataDisplayLabel"; @@ -85,14 +90,8 @@ function ColumnInspector({ currentColumnDetails, currentPanel, datasetId }) { ); } -ColumnInspector.propTypes = { - currentColumnDetails: currentColumnInspectorShape, - currentPanel: PropTypes.string, - datasetId: PropTypes.string -}; - export default connect( - state => ({ + (state: any) => ({ currentColumnDetails: getCurrentColumnDetails(state), currentPanel: state.currentPanel, datasetId: state.metadata && state.metadata.name diff --git a/src/UIComponents/CrossTab.jsx b/src/UIComponents/CrossTab.tsx similarity index 95% rename from src/UIComponents/CrossTab.jsx rename to src/UIComponents/CrossTab.tsx index 4aac9e99..8c7f24e8 100644 --- a/src/UIComponents/CrossTab.jsx +++ b/src/UIComponents/CrossTab.tsx @@ -6,12 +6,16 @@ import { useCallback } from "react"; import { connect } from "react-redux"; import { getCrossTabData } from "../selectors/visualizationSelectors"; -import { styles } from "../constants.js"; +import { styles } from "../constants"; import ScrollableContent from "./ScrollableContent"; -import { crossTabDataShape } from "./shapes"; import I18n from "../i18n"; +import { CrossTabData } from "../types"; -function CrossTab({ crossTabData }) { +interface CrossTabProps { + crossTabData: CrossTabData | null; +} + +function CrossTab({ crossTabData }: CrossTabProps) { const getCellStyle = useCallback((percent) => { return { ...styles["crossTabCell" + Math.round(percent / 20)], @@ -128,10 +132,6 @@ function CrossTab({ crossTabData }) { ); } -CrossTab.propTypes = { - crossTabData: crossTabDataShape -}; - export default connect(state => ({ crossTabData: getCrossTabData(state) }))(CrossTab); diff --git a/src/UIComponents/DataCard.jsx b/src/UIComponents/DataCard.tsx similarity index 89% rename from src/UIComponents/DataCard.jsx rename to src/UIComponents/DataCard.tsx index eb002f59..09092293 100644 --- a/src/UIComponents/DataCard.jsx +++ b/src/UIComponents/DataCard.tsx @@ -1,13 +1,19 @@ /* React component to show information about the currently-selected data set. */ -import PropTypes from "prop-types"; import { connect } from "react-redux"; -import { styles } from "../constants.js"; +import { styles } from "../constants"; import ScrollableContent from "./ScrollableContent"; -import { metadataShape, datasetDetailsShape } from "./shapes.js"; import I18n from "../i18n"; import { getDatasetDetails } from "../helpers/datasetDetails"; -function DataCard({ name, metadata, datasetDetails, dataLength, removedRowsCount }) { +interface DataCardProps { + name?: string; + metadata?: any; + datasetDetails?: any; + dataLength?: number; + removedRowsCount?: number; +} + +function DataCard({ name, metadata, datasetDetails, dataLength, removedRowsCount }: DataCardProps) { const card = metadata && metadata.card; const dataLengthLimit = 20000; @@ -95,15 +101,7 @@ function DataCard({ name, metadata, datasetDetails, dataLength, removedRowsCount ); } -DataCard.propTypes = { - name: PropTypes.string, - metadata: metadataShape, - datasetDetails: datasetDetailsShape, - dataLength: PropTypes.number, - removedRowsCount: PropTypes.number -}; - -export default connect(state => ({ +export default connect((state: any) => ({ name: state.name, metadata: state.metadata, datasetDetails: getDatasetDetails(state), diff --git a/src/UIComponents/DataDisplay.jsx b/src/UIComponents/DataDisplay.tsx similarity index 86% rename from src/UIComponents/DataDisplay.jsx rename to src/UIComponents/DataDisplay.tsx index 3bf97a8a..2e2dc5e1 100644 --- a/src/UIComponents/DataDisplay.jsx +++ b/src/UIComponents/DataDisplay.tsx @@ -1,12 +1,15 @@ /* React component to handle displaying imported data. */ -import PropTypes from "prop-types"; import { connect } from "react-redux"; import Statement from "./Statement"; import DataTable from "./DataTable"; import { styles } from "../constants"; import I18n from "../i18n"; -function DataDisplay({ data }) { +interface DataDisplayProps { + data?: any[]; +} + +function DataDisplay({ data }: DataDisplayProps) { if (data.length === 0) { return null; } @@ -29,12 +32,8 @@ function DataDisplay({ data }) { ); } -DataDisplay.propTypes = { - data: PropTypes.array -}; - export default connect( - state => ({ + (state: any) => ({ data: state.data }) )(DataDisplay); diff --git a/src/UIComponents/DataTable.jsx b/src/UIComponents/DataTable.tsx similarity index 89% rename from src/UIComponents/DataTable.jsx rename to src/UIComponents/DataTable.tsx index 1d3a357c..4d59cf93 100644 --- a/src/UIComponents/DataTable.jsx +++ b/src/UIComponents/DataTable.tsx @@ -1,9 +1,26 @@ /* React component to handle displaying imported data. */ -import PropTypes from "prop-types"; import { connect } from "react-redux"; import { getTableData, setCurrentColumn, setHighlightColumn } from "../redux"; import { styles } from "../constants"; -import { getLocalizedColumnName } from "../helpers/columnDetails.js"; +import { getLocalizedColumnName } from "../helpers/columnDetails"; + +interface DataTableProps { + currentPanel: string; + data: any[]; + datasetId: string; + labelColumn: string; + selectedFeatures: string[]; + setCurrentColumn: (column: string | undefined) => void; + setHighlightColumn: (column: string | undefined) => void; + currentColumn: string; + highlightColumn: string; + reducedColumns: boolean; + singleRow: number | undefined; + startingRow: number | undefined; + noLabel: boolean; + hideLabel: boolean; + useResultsData?: boolean; +} function DataTable({ currentPanel, @@ -20,7 +37,7 @@ function DataTable({ startingRow, noLabel, hideLabel -}) { +}: DataTableProps) { const getColumnHeaderStyle = key => { let style; @@ -155,23 +172,6 @@ function DataTable({ ); } -DataTable.propTypes = { - currentPanel: PropTypes.string, - data: PropTypes.array, - datasetId: PropTypes.string, - labelColumn: PropTypes.string, - selectedFeatures: PropTypes.array, - setCurrentColumn: PropTypes.func, - setHighlightColumn: PropTypes.func, - currentColumn: PropTypes.string, - highlightColumn: PropTypes.string, - reducedColumns: PropTypes.bool, - singleRow: PropTypes.number, - startingRow: PropTypes.number, - noLabel: PropTypes.bool, - hideLabel: PropTypes.bool -}; - export default connect( (state, props) => ({ data: getTableData(state, props.useResultsData), diff --git a/src/UIComponents/GenerateResults.jsx b/src/UIComponents/GenerateResults.tsx similarity index 95% rename from src/UIComponents/GenerateResults.jsx rename to src/UIComponents/GenerateResults.tsx index 03fcf9e2..156b7ed0 100644 --- a/src/UIComponents/GenerateResults.jsx +++ b/src/UIComponents/GenerateResults.tsx @@ -1,5 +1,4 @@ /* React component to handle training. */ -import PropTypes from "prop-types"; import { useState, useEffect, useRef, useCallback } from "react"; import { connect } from "react-redux"; import { getTableData, readyToTrain } from "../redux"; @@ -15,7 +14,15 @@ import I18n from "../i18n"; const framesPerCycle = 80; const maxNumItems = 7; -function GenerateResults({ data, readyToTrain, labelColumn, selectedFeatures, instructionsOverlayActive }) { +interface GenerateResultsProps { + data: any[]; + readyToTrain: boolean; + labelColumn: string; + selectedFeatures: string[]; + instructionsOverlayActive: boolean; +} + +function GenerateResults({ data, readyToTrain, labelColumn, selectedFeatures, instructionsOverlayActive }: GenerateResultsProps) { const [frame, setFrame] = useState(0); const [, setFinished] = useState(false); const frameRef = useRef(0); @@ -192,14 +199,6 @@ function GenerateResults({ data, readyToTrain, labelColumn, selectedFeatures, in ); } -GenerateResults.propTypes = { - data: PropTypes.array, - readyToTrain: PropTypes.bool, - labelColumn: PropTypes.string, - selectedFeatures: PropTypes.array, - instructionsOverlayActive: PropTypes.bool -}; - export default connect(state => ({ data: getTableData(state, true), readyToTrain: readyToTrain(state), diff --git a/src/UIComponents/ModelCard.jsx b/src/UIComponents/ModelCard.tsx similarity index 92% rename from src/UIComponents/ModelCard.jsx rename to src/UIComponents/ModelCard.tsx index d0c8a156..d32eefe1 100644 --- a/src/UIComponents/ModelCard.jsx +++ b/src/UIComponents/ModelCard.tsx @@ -1,5 +1,4 @@ /* React component to handle displaying the model card. */ -import PropTypes from "prop-types"; import { connect } from "react-redux"; import { styles } from "../constants"; import { getLabelToSave, getFeaturesToSave } from "../redux"; @@ -7,11 +6,20 @@ import { getPercentCorrect } from "../helpers/accuracy"; import { getDatasetDetails } from "../helpers/datasetDetails"; import Statement from "./Statement"; import aiBotBorder from "@public/images/ai-bot/ai-bot-border.png"; -import { datasetDetailsShape, trainedModelDetailsShape, modelCardColumnShape } from "./shapes"; import I18n from "../i18n"; -import { getLocalizedColumnName } from "../helpers/columnDetails.js"; +import { getLocalizedColumnName } from "../helpers/columnDetails"; +import { ModelCardColumn } from "../types"; -function ModelCard({ trainedModelDetails, selectedFeatures, percentCorrect, label, features, datasetDetails }) { +interface ModelCardProps { + trainedModelDetails?: any; + selectedFeatures?: string[]; + percentCorrect?: string; + label?: ModelCardColumn; + features?: ModelCardColumn[]; + datasetDetails?: any; +} + +function ModelCard({ trainedModelDetails, selectedFeatures, percentCorrect, label, features, datasetDetails }: ModelCardProps) { console.log("trainedModelDetails", trainedModelDetails) const localizedLabel = getLocalizedColumnName(datasetDetails.name, label.id); const localizedFeatures = @@ -144,16 +152,7 @@ function ModelCard({ trainedModelDetails, selectedFeatures, percentCorrect, labe ); } -ModelCard.propTypes = { - trainedModelDetails: trainedModelDetailsShape, - selectedFeatures: PropTypes.arrayOf(modelCardColumnShape), - percentCorrect: PropTypes.string, - label: modelCardColumnShape, - features: PropTypes.arrayOf(PropTypes.string), - datasetDetails: datasetDetailsShape -}; - -export default connect(state => ({ +export default connect((state: any) => ({ trainedModelDetails: state.trainedModelDetails, selectedFeatures: state.selectedFeatures, percentCorrect: getPercentCorrect(state), diff --git a/src/UIComponents/Predict.jsx b/src/UIComponents/Predict.tsx similarity index 84% rename from src/UIComponents/Predict.jsx rename to src/UIComponents/Predict.tsx index 3d75bf9a..236db256 100644 --- a/src/UIComponents/Predict.jsx +++ b/src/UIComponents/Predict.tsx @@ -1,7 +1,7 @@ /* React component to handle predicting and displaying predictions. */ -import PropTypes from "prop-types"; +import React from "react"; import { connect } from "react-redux"; -import { store } from "../index.js"; +import { store } from "../index"; import train from "../train"; import { setTestData, getPredictAvailable } from "../redux"; import { getConvertedPredictedLabel } from "../helpers/valueConversion"; @@ -15,7 +15,20 @@ import { styles } from "../constants"; import aiBotBorder from "@public/images/ai-bot/ai-bot-border.png"; import ScrollableContent from "./ScrollableContent"; import I18n from "../i18n"; -import { getLocalizedColumnName } from "../helpers/columnDetails.js"; +import { getLocalizedColumnName } from "../helpers/columnDetails"; + +interface PredictProps { + labelColumn: string; + selectedCategoricalFeatures: string[]; + selectedNumericalFeatures: string[]; + uniqueOptionsByColumn: Record; + testData: Record; + setTestData: (feature: string, value: any) => void; + predictedLabel: string | number; + getPredictAvailable: boolean; + extremaByColumn: Record; + datasetId: string; +} function Predict({ labelColumn, @@ -28,8 +41,8 @@ function Predict({ getPredictAvailable: predictAvailable, extremaByColumn, datasetId -}) { - const handleChange = (event, feature) => { +}: PredictProps) { + const handleChange = (event: React.ChangeEvent, feature: string) => { setTestData(feature, event.target.value); }; @@ -43,8 +56,8 @@ function Predict({
{selectedNumericalFeatures.map((feature, index) => { - let min = extremaByColumn[feature].min.toFixed(2); - let max = extremaByColumn[feature].max.toFixed(2); + const min = extremaByColumn[feature].min.toFixed(2); + const max = extremaByColumn[feature].max.toFixed(2); return (
@@ -127,21 +140,8 @@ function Predict({ ); } -Predict.propTypes = { - labelColumn: PropTypes.string, - selectedCategoricalFeatures: PropTypes.array, - selectedNumericalFeatures: PropTypes.array, - uniqueOptionsByColumn: PropTypes.object, - testData: PropTypes.object, - setTestData: PropTypes.func.isRequired, - predictedLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - getPredictAvailable: PropTypes.bool, - extremaByColumn: PropTypes.object, - datasetId: PropTypes.string -}; - export default connect( - state => ({ + (state: any) => ({ testData: state.testData, predictedLabel: getConvertedPredictedLabel(state), labelColumn: state.labelColumn, @@ -152,8 +152,8 @@ export default connect( extremaByColumn: getExtremaByColumn(state), datasetId: state.metadata && state.metadata.name }), - dispatch => ({ - setTestData(feature, value) { + (dispatch: any) => ({ + setTestData(feature: string, value: any) { dispatch(setTestData(feature, value)); } }) diff --git a/src/UIComponents/Results.jsx b/src/UIComponents/Results.tsx similarity index 93% rename from src/UIComponents/Results.jsx rename to src/UIComponents/Results.tsx index 8189706b..8e40f4b7 100644 --- a/src/UIComponents/Results.jsx +++ b/src/UIComponents/Results.tsx @@ -1,5 +1,4 @@ /* React component to handle displaying accuracy results. */ -import PropTypes from "prop-types"; import { useEffect, useCallback } from "react"; import { connect } from "react-redux"; import { styles } from "../constants"; @@ -9,7 +8,14 @@ import ResultsDetails from "./ResultsDetails"; import ScrollableContent from "./ScrollableContent"; import I18n from "../i18n"; -function Results({ historicResults, showResultsDetails, setShowResultsDetails, setResultsPhase }) { +interface ResultsProps { + historicResults: any[]; + showResultsDetails: boolean; + setShowResultsDetails: (show: boolean) => void; + setResultsPhase: (phase: number) => void; +} + +function Results({ historicResults, showResultsDetails, setShowResultsDetails, setResultsPhase }: ResultsProps) { useEffect(() => { setResultsPhase(0); const timer = setTimeout(() => { @@ -83,13 +89,6 @@ function Results({ historicResults, showResultsDetails, setShowResultsDetails, s ); } -Results.propTypes = { - historicResults: PropTypes.array, - showResultsDetails: PropTypes.bool, - setShowResultsDetails: PropTypes.func, - setResultsPhase: PropTypes.func -}; - export default connect( state => ({ historicResults: state.historicResults, diff --git a/src/UIComponents/ResultsDetails.jsx b/src/UIComponents/ResultsDetails.tsx similarity index 82% rename from src/UIComponents/ResultsDetails.jsx rename to src/UIComponents/ResultsDetails.tsx index ce91762e..12ac28de 100644 --- a/src/UIComponents/ResultsDetails.jsx +++ b/src/UIComponents/ResultsDetails.tsx @@ -1,5 +1,4 @@ /* React component to handle displaying accuracy results. */ -import PropTypes from "prop-types"; import { useCallback } from "react"; import { connect } from "react-redux"; import { setShowResultsDetails } from "../redux"; @@ -9,13 +8,22 @@ import { getIncorrectResults } from "../helpers/accuracy"; import { ResultsGrades, styles } from "../constants"; -import { resultsPropType } from "./shapes"; import ResultsToggle from "./ResultsToggle"; import ResultsTable from "./ResultsTable"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faTimes } from "@fortawesome/free-solid-svg-icons"; -function ResultsDetails({ resultsTab, selectedFeatures, labelColumn, percentCorrect, setShowResultsDetails, correctResults, incorrectResults }) { +interface ResultsDetailsProps { + resultsTab: string; + selectedFeatures: string[]; + labelColumn: string; + percentCorrect: string; + setShowResultsDetails: (show: boolean) => void; + correctResults: any; + incorrectResults: any; +} + +function ResultsDetails({ resultsTab, selectedFeatures, labelColumn, percentCorrect, setShowResultsDetails, correctResults, incorrectResults }: ResultsDetailsProps) { const onClose = useCallback(() => { setShowResultsDetails(false); }, [setShowResultsDetails]); @@ -44,16 +52,6 @@ function ResultsDetails({ resultsTab, selectedFeatures, labelColumn, percentCorr ); } -ResultsDetails.propTypes = { - resultsTab: PropTypes.string, - selectedFeatures: PropTypes.array, - labelColumn: PropTypes.string, - percentCorrect: PropTypes.string, - setShowResultsDetails: PropTypes.func, - correctResults: resultsPropType, - incorrectResults: resultsPropType, -}; - export default connect( state => ({ resultsTab: state.resultsTab, diff --git a/src/UIComponents/ResultsTable.jsx b/src/UIComponents/ResultsTable.tsx similarity index 92% rename from src/UIComponents/ResultsTable.jsx rename to src/UIComponents/ResultsTable.tsx index fb36c929..d24aaf47 100644 --- a/src/UIComponents/ResultsTable.jsx +++ b/src/UIComponents/ResultsTable.tsx @@ -1,14 +1,23 @@ /* React component to handle displaying test data and A.I. Bot's guesses. */ -import PropTypes from "prop-types"; import { useCallback } from "react"; import { connect } from "react-redux"; import { isRegression, setResultsHighlightRow } from "../redux"; import { styles, colors, REGRESSION_ERROR_TOLERANCE } from "../constants"; -import { resultsPropType } from "./shapes"; import I18n from "../i18n"; -import { getLocalizedColumnName } from "../helpers/columnDetails.js"; +import { getLocalizedColumnName } from "../helpers/columnDetails"; +import { ResultsData } from "../types"; -function ResultsTable({ selectedFeatures, labelColumn, results, isRegression: isRegressionMode, setResultsHighlightRow, resultsHighlightRow, datasetId }) { +interface ResultsTableProps { + selectedFeatures: string[]; + labelColumn: string; + results: ResultsData; + isRegression: boolean; + setResultsHighlightRow: (row: number | undefined) => void; + resultsHighlightRow: number | undefined; + datasetId: string; +} + +function ResultsTable({ selectedFeatures, labelColumn, results, isRegression: isRegressionMode, setResultsHighlightRow, resultsHighlightRow, datasetId }: ResultsTableProps) { const getRowCellStyle = useCallback((index) => { return { ...styles.tableCell, @@ -126,16 +135,6 @@ function ResultsTable({ selectedFeatures, labelColumn, results, isRegression: is ); } -ResultsTable.propTypes = { - selectedFeatures: PropTypes.array, - labelColumn: PropTypes.string, - results: resultsPropType, - isRegression: PropTypes.bool, - setResultsHighlightRow: PropTypes.func, - resultsHighlightRow: PropTypes.number, - datasetId: PropTypes.string -}; - export default connect( state => ({ selectedFeatures: state.selectedFeatures, diff --git a/src/UIComponents/ResultsToggle.jsx b/src/UIComponents/ResultsToggle.tsx similarity index 84% rename from src/UIComponents/ResultsToggle.jsx rename to src/UIComponents/ResultsToggle.tsx index ba0ca997..117efe2a 100644 --- a/src/UIComponents/ResultsToggle.jsx +++ b/src/UIComponents/ResultsToggle.tsx @@ -1,5 +1,4 @@ /* React component to handle toggling between correct/incorrect test results */ -import PropTypes from "prop-types"; import { connect } from "react-redux"; import { setResultsTab } from "../redux"; import { ResultsGrades, styles } from "../constants"; @@ -7,8 +6,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faTimes, faCheck } from "@fortawesome/free-solid-svg-icons"; import I18n from "../i18n"; -function ResultsToggle({ resultsTab, setResultsTab }) { - const getTogglePillStyle = key => { +interface ResultsToggleProps { + resultsTab?: string; + setResultsTab?: (key: string) => void; +} + +function ResultsToggle({ resultsTab, setResultsTab }: ResultsToggleProps) { + const getTogglePillStyle = (key: string) => { let style; if (key === resultsTab) { style = { ...styles.pill, ...styles.selectedPill }; @@ -54,17 +58,12 @@ function ResultsToggle({ resultsTab, setResultsTab }) { ); } -ResultsToggle.propTypes = { - resultsTab: PropTypes.string, - setResultsTab: PropTypes.func -}; - export default connect( - state => ({ + (state: any) => ({ resultsTab: state.resultsTab }), dispatch => ({ - setResultsTab(key) { + setResultsTab(key: string) { dispatch(setResultsTab(key)); } }) diff --git a/src/UIComponents/SaveModel.jsx b/src/UIComponents/SaveModel.tsx similarity index 88% rename from src/UIComponents/SaveModel.jsx rename to src/UIComponents/SaveModel.tsx index 9283da2c..733f7a7d 100644 --- a/src/UIComponents/SaveModel.jsx +++ b/src/UIComponents/SaveModel.tsx @@ -1,6 +1,5 @@ /* React component to handle saving a trained model. */ -import PropTypes from "prop-types"; -import { useState } from "react"; +import React, { useState } from "react"; import { connect } from "react-redux"; import { setTrainedModelDetail } from "../redux"; import { @@ -12,7 +11,18 @@ import { styles, ModelNameMaxLength } from "../constants"; import Statement from "./Statement"; import ScrollableContent from "./ScrollableContent"; import I18n from "../i18n"; -import { getLocalizedColumnName } from "../helpers/columnDetails.js"; +import { getLocalizedColumnName } from "../helpers/columnDetails"; + +interface SaveModelProps { + trainedModel: any; + setTrainedModelDetail: (field: string, value: string, isColumn: boolean) => void; + trainedModelDetails: any; + labelColumn: string; + columnDescriptions: { id: string; description: string }[]; + dataDescription: string; + isUserUploadedDataset: boolean; + datasetId: string; +} function SaveModel({ trainedModel, @@ -23,19 +33,19 @@ function SaveModel({ dataDescription, isUserUploadedDataset: isUserUploaded, datasetId -}) { +}: SaveModelProps) { const [showColumnDescriptions, setShowColumnDescriptions] = useState(isUserUploaded); const toggleColumnDescriptions = () => { setShowColumnDescriptions(!showColumnDescriptions); }; - const handleChange = (event, field, isColumn) => { + const handleChange = (event: React.ChangeEvent, field: string, isColumn: boolean) => { setTrainedModelDetail(field, event.target.value, isColumn); }; const getColumnFields = () => { - var fields = []; + const fields: any[] = []; for (const columnDescription of columnDescriptions) { const labelType = I18n.t("saveModelColumnTypeLabel"); @@ -54,7 +64,7 @@ function SaveModel({ }; const getUsesFields = () => { - var fields = []; + const fields: any[] = []; fields.push({ id: "potentialUses", text: I18n.t("potentialUsesLabel"), @@ -79,7 +89,7 @@ function SaveModel({ const nameField = { id: "name", text: I18n.t("modelNameLabel") - }; + } as any; const dataDescriptionField = { id: "datasetDescription", @@ -120,7 +130,7 @@ function SaveModel({
{field.description}
    {field.descriptionDetails && - field.descriptionDetails.map((detail, index) => { + field.descriptionDetails.map((detail: string, index: number) => { return (
  • {detail} @@ -131,7 +141,7 @@ function SaveModel({ {!field.answer && (