diff --git a/webapp/.eslintrc.json b/webapp/.eslintrc.json index aec6385bd..4e5710d09 100644 --- a/webapp/.eslintrc.json +++ b/webapp/.eslintrc.json @@ -1,21 +1,16 @@ { "extends": [ - "eslint:recommended", - "plugin:react-hooks/recommended" + "eslint:recommended", + "plugin:react-hooks/recommended" ], + "parser": "@typescript-eslint/parser", "parserOptions": { - "ecmaVersion": 8, - "sourceType": "module", - "ecmaFeatures": { - "jsx": true, - "impliedStrict": true, - "modules": true, - "experimentalObjectRestSpread": true - } + "project": "./tsconfig.json", + "tsconfigRootDir": "./" }, - "parser": "babel-eslint", "plugins": [ "react", + "@typescript-eslint", "import" ], "env": { @@ -35,7 +30,12 @@ "beforeEach": true }, "settings": { - "import/resolver": "webpack" + "import/resolver": { + "typescript": {} + }, + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx"] + } }, "rules": { "array-bracket-spacing": [ @@ -639,7 +639,7 @@ ], "rules": { "@typescript-eslint/ban-ts-ignore": 0, - "@typescript-eslint/ban-types": 1, + "@typescript-eslint/ban-types": 0, "@typescript-eslint/ban-ts-comment": 0, "@typescript-eslint/no-var-requires": 0, "@typescript-eslint/prefer-interface": 0, diff --git a/webapp/package-lock.json b/webapp/package-lock.json index bce4e980c..0d3af8738 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -42,6 +42,7 @@ "@types/react-intl": "3.0.0", "@types/react-redux": "7.1.9", "@types/react-router-dom": "5.1.5", + "@types/react-select": "3.1.0", "@types/react-transition-group": "4.4.0", "@typescript-eslint/eslint-plugin": "4.1.1", "@typescript-eslint/parser": "4.1.1", @@ -54,6 +55,7 @@ "enzyme-adapter-react-16": "1.15.4", "enzyme-to-json": "3.5.0", "eslint": "7.9.0", + "eslint-import-resolver-typescript": "3.6.1", "eslint-import-resolver-webpack": "0.12.2", "eslint-plugin-import": "2.22.0", "eslint-plugin-react": "7.20.6", @@ -5415,6 +5417,17 @@ "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", "dev": true }, + "node_modules/@types/react-select": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.1.0.tgz", + "integrity": "sha512-INfN1SkxmmhQxwHizPck2sBmdh7rEe0WrP4bMf1t7HAoQAX0G0nEqVrgX67h56hoaeA6+OImj/caIKEhwPkViQ==", + "dev": true, + "dependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "@types/react-transition-group": "*" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", @@ -9134,6 +9147,53 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/eslint-import-resolver-webpack": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.2.tgz", @@ -10494,6 +10554,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -19730,6 +19802,15 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -27817,6 +27898,17 @@ "@types/react-router": "*" } }, + "@types/react-select": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.1.0.tgz", + "integrity": "sha512-INfN1SkxmmhQxwHizPck2sBmdh7rEe0WrP4bMf1t7HAoQAX0G0nEqVrgX67h56hoaeA6+OImj/caIKEhwPkViQ==", + "dev": true, + "requires": { + "@types/react": "*", + "@types/react-dom": "*", + "@types/react-transition-group": "*" + } + }, "@types/react-transition-group": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", @@ -30801,6 +30893,39 @@ } } }, + "eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "dependencies": { + "enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + } + } + }, "eslint-import-resolver-webpack": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.2.tgz", @@ -31792,6 +31917,15 @@ "get-intrinsic": "^1.2.4" } }, + "get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -38804,6 +38938,12 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", diff --git a/webapp/package.json b/webapp/package.json index 5446b233d..41156d260 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -34,6 +34,7 @@ "@types/react-intl": "3.0.0", "@types/react-redux": "7.1.9", "@types/react-router-dom": "5.1.5", + "@types/react-select": "3.1.0", "@types/react-transition-group": "4.4.0", "@typescript-eslint/eslint-plugin": "4.1.1", "@typescript-eslint/parser": "4.1.1", @@ -46,6 +47,7 @@ "enzyme-adapter-react-16": "1.15.4", "enzyme-to-json": "3.5.0", "eslint": "7.9.0", + "eslint-import-resolver-typescript": "3.6.1", "eslint-import-resolver-webpack": "0.12.2", "eslint-plugin-import": "2.22.0", "eslint-plugin-react": "7.20.6", diff --git a/webapp/src/components/github_assignee_selector/github_assignee_selector.jsx b/webapp/src/components/github_assignee_selector/github_assignee_selector.jsx index d33f74a63..68a806081 100644 --- a/webapp/src/components/github_assignee_selector/github_assignee_selector.jsx +++ b/webapp/src/components/github_assignee_selector/github_assignee_selector.jsx @@ -4,7 +4,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import IssueAttributeSelector from 'components/issue_attribute_selector'; +import IssueAttributeSelector from '@/components/issue_attribute_selector'; export default class GithubAssigneeSelector extends PureComponent { static propTypes = { diff --git a/webapp/src/components/github_issue_selector.jsx b/webapp/src/components/github_issue_selector.jsx index 34fb037e8..f3c82fb0a 100644 --- a/webapp/src/components/github_issue_selector.jsx +++ b/webapp/src/components/github_issue_selector.jsx @@ -7,8 +7,8 @@ import PropTypes from 'prop-types'; import debounce from 'debounce-promise'; import AsyncSelect from 'react-select/async'; -import {getStyleForReactSelect} from 'utils/styles'; -import Client from 'client'; +import {getStyleForReactSelect} from '@/utils/styles'; +import Client from '@/client'; const searchDebounceDelay = 400; diff --git a/webapp/src/components/github_label_selector/github_label_selector.jsx b/webapp/src/components/github_label_selector/github_label_selector.tsx similarity index 60% rename from webapp/src/components/github_label_selector/github_label_selector.jsx rename to webapp/src/components/github_label_selector/github_label_selector.tsx index 71d1087b0..02fbaaf25 100644 --- a/webapp/src/components/github_label_selector/github_label_selector.jsx +++ b/webapp/src/components/github_label_selector/github_label_selector.tsx @@ -2,21 +2,25 @@ // See LICENSE.txt for license information. import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; - -import IssueAttributeSelector from 'components/issue_attribute_selector'; - -export default class GithubLabelSelector extends PureComponent { - static propTypes = { - repoName: PropTypes.string.isRequired, - theme: PropTypes.object.isRequired, - selectedLabels: PropTypes.array.isRequired, - onChange: PropTypes.func.isRequired, - actions: PropTypes.shape({ - getLabelOptions: PropTypes.func.isRequired, - }).isRequired, - }; +import {Theme} from 'mattermost-redux/types/preferences'; + +import IssueAttributeSelector, {IssueAttributeSelectorSelection} from '../issue_attribute_selector'; + +import {GitHubLabelSelectorDispatchProps} from '.'; + +type Props = GitHubLabelSelectorDispatchProps & { + repoName: string; + theme: Theme; + selectedLabels: string[]; + onChange: (selection: string[]) => void; +}; + +type Option = { + name: string; +}; + +export default class GithubLabelSelector extends PureComponent { loadLabels = async () => { if (this.props.repoName === '') { return []; @@ -32,13 +36,19 @@ export default class GithubLabelSelector extends PureComponent { return []; } - return options.data.map((option) => ({ + return options.data.map((option: Option) => ({ value: option.name, label: option.name, })); }; - onChange = (selection) => this.props.onChange(selection.map((s) => s.value)); + onChange = (selection: IssueAttributeSelectorSelection) => { + if (!selection || !Array.isArray(selection)) { + return; + } + + this.props.onChange(selection.map((s) => s.value)); + } render() { return ( diff --git a/webapp/src/components/github_label_selector/index.js b/webapp/src/components/github_label_selector/index.js deleted file mode 100644 index 18aabdabe..000000000 --- a/webapp/src/components/github_label_selector/index.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {connect} from 'react-redux'; -import {bindActionCreators} from 'redux'; - -import {getLabelOptions} from '../../actions'; - -import GithubLabelSelector from './github_label_selector.jsx'; - -const mapDispatchToProps = (dispatch) => ({ - actions: bindActionCreators({getLabelOptions}, dispatch), -}); - -export default connect( - null, - mapDispatchToProps, -)(GithubLabelSelector); diff --git a/webapp/src/components/github_label_selector/index.ts b/webapp/src/components/github_label_selector/index.ts new file mode 100644 index 000000000..cd66adf4c --- /dev/null +++ b/webapp/src/components/github_label_selector/index.ts @@ -0,0 +1,26 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {connect} from 'react-redux'; +import {Dispatch, bindActionCreators} from 'redux'; + +import {getLabelOptions} from '../../actions'; + +import GithubLabelSelector from './github_label_selector'; + +const mapDispatchToProps = (dispatch: Dispatch) => ({ + actions: bindActionCreators({getLabelOptions}, dispatch), +}) as unknown as Actions; + +type Actions = { + getLabelOptions: (repoName: string) => ReturnType>; +}; + +export type GitHubLabelSelectorDispatchProps = { + actions: Actions; +}; + +export default connect( + null, + mapDispatchToProps, +)(GithubLabelSelector); diff --git a/webapp/src/components/github_milestone_selector/github_milestone_selector.jsx b/webapp/src/components/github_milestone_selector/github_milestone_selector.jsx index ba390c1d0..444e7f6db 100644 --- a/webapp/src/components/github_milestone_selector/github_milestone_selector.jsx +++ b/webapp/src/components/github_milestone_selector/github_milestone_selector.jsx @@ -4,7 +4,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import IssueAttributeSelector from 'components/issue_attribute_selector'; +import IssueAttributeSelector from '@/components/issue_attribute_selector'; export default class GithubMilestoneSelector extends PureComponent { static propTypes = { diff --git a/webapp/src/components/github_repo_selector/github_repo_selector.jsx b/webapp/src/components/github_repo_selector/github_repo_selector.jsx index c6352203a..301b67d6a 100644 --- a/webapp/src/components/github_repo_selector/github_repo_selector.jsx +++ b/webapp/src/components/github_repo_selector/github_repo_selector.jsx @@ -4,7 +4,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import ReactSelectSetting from 'components/react_select_setting'; +import ReactSelectSetting from '@/components/react_select_setting'; const initialState = { invalid: false, diff --git a/webapp/src/components/github_repo_selector/index.js b/webapp/src/components/github_repo_selector/index.js index 43616df85..a096ce2fe 100644 --- a/webapp/src/components/github_repo_selector/index.js +++ b/webapp/src/components/github_repo_selector/index.js @@ -4,7 +4,8 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import manifest from 'manifest'; +import manifest from '@/manifest'; + import {getRepos} from '../../actions'; import GithubRepoSelector from './github_repo_selector.jsx'; diff --git a/webapp/src/components/issue_attribute_selector.jsx b/webapp/src/components/issue_attribute_selector.tsx similarity index 60% rename from webapp/src/components/issue_attribute_selector.jsx rename to webapp/src/components/issue_attribute_selector.tsx index 54b32278e..dbe1b7b2c 100644 --- a/webapp/src/components/issue_attribute_selector.jsx +++ b/webapp/src/components/issue_attribute_selector.tsx @@ -2,26 +2,37 @@ // See LICENSE.txt for license information. import React, {PureComponent} from 'react'; -import ReactSelect from 'react-select'; -import PropTypes from 'prop-types'; - -import {getStyleForReactSelect} from 'utils/styles'; -import Setting from 'components/setting'; - -export default class IssueAttributeSelector extends PureComponent { - static propTypes = { - isMulti: PropTypes.bool.isRequired, - repoName: PropTypes.string.isRequired, - theme: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - loadOptions: PropTypes.func.isRequired, - selection: PropTypes.oneOfType([ - PropTypes.array, - PropTypes.object, - ]).isRequired, - }; +import ReactSelect, {ValueType, ActionMeta} from 'react-select'; + +import {Theme} from 'mattermost-redux/types/preferences'; + +import {getStyleForReactSelect} from '@/utils/styles'; +import Setting from '@/components/setting'; + +export type ReactSelectOption = { + label: string; + value: string; +}; + +export type IssueAttributeSelectorSelection = ReactSelectOption | ReactSelectOption[] | null; - constructor(props) { +export type Props = { + isMulti: boolean; + repoName: string; + theme: Theme; + onChange: (selection: ReactSelectOption | ReactSelectOption[] | null) => void; + loadOptions: () => Promise; + selection: ReactSelectOption | string[] | null; +}; + +type State = { + options: ReactSelectOption[]; + isLoading: boolean; + error: Error | null; +}; + +export default class IssueAttributeSelector extends PureComponent { + constructor(props: Props) { super(props); this.state = { @@ -37,7 +48,7 @@ export default class IssueAttributeSelector extends PureComponent { } } - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: Props) { if (this.props.repoName && prevProps.repoName !== this.props.repoName) { this.loadOptions(); } @@ -56,16 +67,18 @@ export default class IssueAttributeSelector extends PureComponent { }); } catch (err) { this.filterSelection([]); + const error = err instanceof Error ? err : new Error('An unexpected error occurred'); this.setState({ - error: err, + error, isLoading: false, }); } }; - filterSelection = (options) => { - if (this.props.isMulti) { - const filtered = options.filter((option) => this.props.selection.includes(option.value)); + filterSelection = (options: ReactSelectOption[]) => { + if (this.props.isMulti || Array.isArray(this.props.selection)) { + const selection = this.props.selection as string[] | null; + const filtered = options.filter((option) => selection?.includes(option.value)); this.props.onChange(filtered); return; } @@ -85,29 +98,31 @@ export default class IssueAttributeSelector extends PureComponent { this.props.onChange(null); } - onChange = (selection) => { + onChange = (selection: ValueType, actionMeta: ActionMeta) => { if (this.props.isMulti) { - this.props.onChange(selection || []); + this.props.onChange((selection as ReactSelectOption[]) || []); return; } - this.props.onChange(selection); + this.props.onChange(selection as ReactSelectOption | null); }; render() { - let selection; - if (this.props.isMulti) { + let selection: ReactSelectOption | ReactSelectOption[] | null; + if (Array.isArray(this.props.selection)) { selection = this.props.selection.map((s) => ({label: s, value: s})); } else { - selection = this.props.selection || {}; + selection = this.props.selection; } const noOptionsMessage = this.props.repoName ? 'No options' : 'Please select a repository first'; + const {theme, ...props} = this.props; + return ( noOptionsMessage} @@ -117,7 +132,7 @@ export default class IssueAttributeSelector extends PureComponent { options={this.state.options} value={selection} isLoading={this.state.isLoading} - styles={getStyleForReactSelect(this.props.theme)} + styles={getStyleForReactSelect(theme)} /> {this.state.error && ( diff --git a/webapp/src/components/link_tooltip/index.jsx b/webapp/src/components/link_tooltip/index.jsx index 0dfad4d4c..00bd19fa4 100644 --- a/webapp/src/components/link_tooltip/index.jsx +++ b/webapp/src/components/link_tooltip/index.jsx @@ -3,7 +3,7 @@ import {connect} from 'react-redux'; -import manifest from 'manifest'; +import manifest from '@/manifest'; import {LinkTooltip} from './link_tooltip'; diff --git a/webapp/src/components/link_tooltip/link_tooltip.jsx b/webapp/src/components/link_tooltip/link_tooltip.jsx index c382909ab..4dcd65df2 100644 --- a/webapp/src/components/link_tooltip/link_tooltip.jsx +++ b/webapp/src/components/link_tooltip/link_tooltip.jsx @@ -4,7 +4,8 @@ import './tooltip.css'; import {GitMergeIcon, GitPullRequestIcon, IssueClosedIcon, IssueOpenedIcon} from '@primer/octicons-react'; import ReactMarkdown from 'react-markdown'; -import Client from 'client'; +import Client from '@/client'; + import {getLabelFontColor, hexToRGB} from '../../utils/styles'; const maxTicketDescriptionLength = 160; diff --git a/webapp/src/components/modals/attach_comment_to_issue/attach_comment_to_issue.jsx b/webapp/src/components/modals/attach_comment_to_issue/attach_comment_to_issue.jsx index 703adc28f..2e996df0c 100644 --- a/webapp/src/components/modals/attach_comment_to_issue/attach_comment_to_issue.jsx +++ b/webapp/src/components/modals/attach_comment_to_issue/attach_comment_to_issue.jsx @@ -5,11 +5,11 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {Modal} from 'react-bootstrap'; -import FormButton from 'components/form_button'; -import Input from 'components/input'; +import FormButton from '@/components/form_button'; +import Input from '@/components/input'; -import GithubIssueSelector from 'components/github_issue_selector'; -import {getErrorMessage} from 'utils/user_utils'; +import GithubIssueSelector from '@/components/github_issue_selector'; +import {getErrorMessage} from '@/utils/user_utils'; const initialState = { submitting: false, diff --git a/webapp/src/components/modals/attach_comment_to_issue/index.js b/webapp/src/components/modals/attach_comment_to_issue/index.js index 89459d209..bade1454b 100644 --- a/webapp/src/components/modals/attach_comment_to_issue/index.js +++ b/webapp/src/components/modals/attach_comment_to_issue/index.js @@ -5,8 +5,8 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; -import manifest from 'manifest'; -import {closeAttachCommentToIssueModal, attachCommentToIssue} from 'actions'; +import manifest from '@/manifest'; +import {closeAttachCommentToIssueModal, attachCommentToIssue} from '@/actions'; import AttachCommentToIssue from './attach_comment_to_issue'; diff --git a/webapp/src/components/modals/create_issue/create_issue.jsx b/webapp/src/components/modals/create_issue/create_issue.jsx index 25354955a..871e398f9 100644 --- a/webapp/src/components/modals/create_issue/create_issue.jsx +++ b/webapp/src/components/modals/create_issue/create_issue.jsx @@ -5,14 +5,14 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {Modal} from 'react-bootstrap'; -import GithubLabelSelector from 'components/github_label_selector'; -import GithubAssigneeSelector from 'components/github_assignee_selector'; -import GithubMilestoneSelector from 'components/github_milestone_selector'; -import GithubRepoSelector from 'components/github_repo_selector'; -import Validator from 'components/validator'; -import FormButton from 'components/form_button'; -import Input from 'components/input'; -import {getErrorMessage} from 'utils/user_utils'; +import GithubLabelSelector from '@/components/github_label_selector'; +import GithubAssigneeSelector from '@/components/github_assignee_selector'; +import GithubMilestoneSelector from '@/components/github_milestone_selector'; +import GithubRepoSelector from '@/components/github_repo_selector'; +import Validator from '@/components/validator'; +import FormButton from '@/components/form_button'; +import Input from '@/components/input'; +import {getErrorMessage} from '@/utils/user_utils'; const MAX_TITLE_LENGTH = 256; diff --git a/webapp/src/components/modals/create_issue/index.js b/webapp/src/components/modals/create_issue/index.js index e75562886..2b5b37017 100644 --- a/webapp/src/components/modals/create_issue/index.js +++ b/webapp/src/components/modals/create_issue/index.js @@ -5,8 +5,8 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; -import manifest from 'manifest'; -import {closeCreateIssueModal, createIssue} from 'actions'; +import manifest from '@/manifest'; +import {closeCreateIssueModal, createIssue} from '@/actions'; import CreateIssueModal from './create_issue'; diff --git a/webapp/src/components/post_menu_action/create_issue/index.js b/webapp/src/components/post_menu_action/create_issue/index.js index d8d1c5a0a..e39c6d322 100644 --- a/webapp/src/components/post_menu_action/create_issue/index.js +++ b/webapp/src/components/post_menu_action/create_issue/index.js @@ -6,8 +6,8 @@ import {bindActionCreators} from 'redux'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {isSystemMessage} from 'mattermost-redux/utils/post_utils'; -import manifest from 'manifest'; -import {openCreateIssueModal} from 'actions'; +import manifest from '@/manifest'; +import {openCreateIssueModal} from '@/actions'; import CreateIssuePostMenuAction from './create_issue'; diff --git a/webapp/src/components/post_menu_actions/attach_comment_to_issue/index.js b/webapp/src/components/post_menu_actions/attach_comment_to_issue/index.js index eb1b2d686..d7b80af28 100644 --- a/webapp/src/components/post_menu_actions/attach_comment_to_issue/index.js +++ b/webapp/src/components/post_menu_actions/attach_comment_to_issue/index.js @@ -6,8 +6,8 @@ import {bindActionCreators} from 'redux'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {isSystemMessage} from 'mattermost-redux/utils/post_utils'; -import manifest from 'manifest'; -import {openAttachCommentToIssueModal} from 'actions'; +import manifest from '@/manifest'; +import {openAttachCommentToIssueModal} from '@/actions'; import AttachCommentToIssuePostMenuAction from './attach_comment_to_issue'; diff --git a/webapp/src/components/react_select_setting.jsx b/webapp/src/components/react_select_setting.jsx index b8cd633e5..b066f660f 100644 --- a/webapp/src/components/react_select_setting.jsx +++ b/webapp/src/components/react_select_setting.jsx @@ -8,8 +8,8 @@ import ReactSelect from 'react-select'; import AsyncSelect from 'react-select/async'; import CreatableSelect from 'react-select/creatable'; -import Setting from 'components/setting'; -import {getStyleForReactSelect} from 'utils/styles'; +import Setting from '@/components/setting'; +import {getStyleForReactSelect} from '@/utils/styles'; const MAX_NUM_OPTIONS = 100; diff --git a/webapp/src/index.js b/webapp/src/index.js index 4b0a50d2b..cf839b2bc 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -1,7 +1,7 @@ // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import AttachCommentToIssuePostMenuAction from 'components/post_menu_actions/attach_comment_to_issue'; -import AttachCommentToIssueModal from 'components/modals/attach_comment_to_issue'; +import AttachCommentToIssuePostMenuAction from '@/components/post_menu_actions/attach_comment_to_issue'; +import AttachCommentToIssueModal from '@/components/modals/attach_comment_to_issue'; import CreateIssueModal from './components/modals/create_issue'; import CreateIssuePostMenuAction from './components/post_menu_action/create_issue'; diff --git a/webapp/src/utils/styles.js b/webapp/src/utils/styles.js index 0f8225564..9964b08c1 100644 --- a/webapp/src/utils/styles.js +++ b/webapp/src/utils/styles.js @@ -5,7 +5,8 @@ import {changeOpacity} from 'mattermost-redux/utils/theme_utils'; export const getStyleForReactSelect = (theme) => { if (!theme) { - return null; + // eslint-disable-next-line no-undefined + return undefined; } return { diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json index 24eae8cde..ba33ca86b 100644 --- a/webapp/tsconfig.json +++ b/webapp/tsconfig.json @@ -20,7 +20,10 @@ "noEmit": true, "experimentalDecorators": true, "jsx": "react", - "baseUrl": "." + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } }, "typeRoots": ["./src/types"], "include": [ diff --git a/webapp/webpack.config.js b/webapp/webpack.config.js index 9d9640fab..edf430d9a 100644 --- a/webapp/webpack.config.js +++ b/webapp/webpack.config.js @@ -1,6 +1,7 @@ const exec = require('child_process').exec; const path = require('path'); + const webpack = require('webpack'); const PLUGIN_ID = require('../plugin.json').id; @@ -44,6 +45,9 @@ module.exports = { './src/index.js', ], resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, modules: [ 'src', 'node_modules',