diff --git a/.eslintrc.json b/.eslintrc.json index 638c08f..a683c1e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -33,6 +33,27 @@ "semi": [ "error", "never" + ], + "@typescript-eslint/ban-types": [ + "warn", + { + "extendDefaults": true, + "types": { + "{}": false + } + } + ], + "@typescript-eslint/no-unused-vars": [ + "warn", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } ] + }, + "settings": { + "react": { + "version": "detect" + } } } diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 92277a4..49e87ef 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -56,7 +56,7 @@ class App extends React.Component { console.log(payload) }) - listen('jar_extracted', ({ payload }) => { + listen('jar_extracted', ({ payload }: { payload: string}) => { setConfigOption('grasscutter_path', payload) }) diff --git a/src/ui/Debug.tsx b/src/ui/Debug.tsx index e70c7df..4846541 100644 --- a/src/ui/Debug.tsx +++ b/src/ui/Debug.tsx @@ -40,7 +40,7 @@ function none() { alert('none') } -class Debug extends React.Component{ +class Debug extends React.Component{ render() { return (
diff --git a/src/ui/components/ServerLaunchSection.tsx b/src/ui/components/ServerLaunchSection.tsx index 3644310..1cf5495 100644 --- a/src/ui/components/ServerLaunchSection.tsx +++ b/src/ui/components/ServerLaunchSection.tsx @@ -11,10 +11,6 @@ import Server from '../../resources/icons/server.svg' import './ServerLaunchSection.css' import {dataDir} from '@tauri-apps/api/path' -interface IProps { - [key: string]: any -} - interface IState { grasscutterEnabled: boolean; buttonLabel: string; @@ -31,8 +27,8 @@ interface IState { httpsEnabled: boolean; } -export default class ServerLaunchSection extends React.Component { - constructor(props: IProps) { +export default class ServerLaunchSection extends React.Component<{}, IState> { + constructor(props: {}) { super(props) this.state = { diff --git a/src/ui/components/TopBar.tsx b/src/ui/components/TopBar.tsx index f1fac63..aeb6ae6 100644 --- a/src/ui/components/TopBar.tsx +++ b/src/ui/components/TopBar.tsx @@ -5,7 +5,6 @@ import closeIcon from '../../resources/icons/close.svg' import minIcon from '../../resources/icons/min.svg' import cogBtn from '../../resources/icons/cog.svg' import downBtn from '../../resources/icons/download.svg' -import gameBtn from '../../resources/icons/game.svg' import Tr from '../../utils/language' diff --git a/src/ui/components/common/BigButton.tsx b/src/ui/components/common/BigButton.tsx index 997e773..5b6cbe7 100644 --- a/src/ui/components/common/BigButton.tsx +++ b/src/ui/components/common/BigButton.tsx @@ -3,7 +3,7 @@ import './BigButton.css' interface IProps { children: React.ReactNode; - onClick: () => any; + onClick: () => unknown; id: string; disabled?: boolean; } @@ -23,7 +23,7 @@ export default class BigButton extends React.Component { this.handleClick = this.handleClick.bind(this) } - static getDerivedStateFromProps(props: IProps, state: IState) { + static getDerivedStateFromProps(props: IProps, _state: IState) { return { disabled: props.disabled } diff --git a/src/ui/components/common/TextInput.tsx b/src/ui/components/common/TextInput.tsx index e2009ea..1efac23 100644 --- a/src/ui/components/common/TextInput.tsx +++ b/src/ui/components/common/TextInput.tsx @@ -12,9 +12,7 @@ interface IProps { id?: string; clearable?: boolean; customClearBehaviour?: () => void; - style?: { - [key: string]: any; - } + style?: React.CSSProperties; } interface IState { diff --git a/src/ui/components/menu/Downloads.tsx b/src/ui/components/menu/Downloads.tsx index 0368a46..59d484e 100644 --- a/src/ui/components/menu/Downloads.tsx +++ b/src/ui/components/menu/Downloads.tsx @@ -8,7 +8,7 @@ import { dataDir } from '@tauri-apps/api/path' import './Downloads.css' import Divider from './Divider' -import { getConfigOption, setConfigOption } from '../../../utils/configuration' +import { getConfigOption } from '../../../utils/configuration' import { invoke } from '@tauri-apps/api' import { listen } from '@tauri-apps/api/event' import HelpButton from '../common/HelpButton' @@ -183,7 +183,7 @@ export default class Downloads extends React.Component { grasscutter_downloading: this.props.downloadManager.downloadingJar(), resources_downloading: this.props.downloadManager.downloadingResources(), repo_downloading: this.props.downloadManager.downloadingRepo(), - grasscutter_set: gc_path && gc_path !== '', + grasscutter_set: gc_path !== '', }) } diff --git a/src/ui/components/news/NewsSection.tsx b/src/ui/components/news/NewsSection.tsx index 3b4638b..861b8c1 100644 --- a/src/ui/components/news/NewsSection.tsx +++ b/src/ui/components/news/NewsSection.tsx @@ -11,8 +11,28 @@ interface IProps { interface IState { selected: string; - news: any; - commitList: any; + news?: JSX.Element; + commitList?: JSX.Element[]; +} + +interface GrasscutterAPIResponse { + commits: { + gc_stable: CommitResponse[]; + gc_dev: CommitResponse[]; + cultivation: CommitResponse[]; + } +} + +interface CommitResponse { + sha: string; + commit: Commit; +} + +interface Commit { + author: { + name: string; + }; + message: string; } export default class NewsSection extends React.Component { @@ -21,8 +41,6 @@ export default class NewsSection extends React.Component { this.state = { selected: props.selected || 'commits', - news: null, - commitList: null } this.setSelected = this.setSelected.bind(this) @@ -42,40 +60,41 @@ export default class NewsSection extends React.Component { async showLatestCommits() { if (!this.state.commitList) { - const commits: string = await invoke('req_get', { url: 'https://api.grasscutter.io/cultivation/query' }) - let obj + const response: string = await invoke('req_get', { url: 'https://api.grasscutter.io/cultivation/query' }) + let grasscutterApiResponse: GrasscutterAPIResponse | null = null try { - obj = JSON.parse(commits) + grasscutterApiResponse = JSON.parse(response) } catch(e) { - obj = {} + grasscutterApiResponse = null } - // If it didn't work, use official API - if (!obj.commits) { - const commits: string = await invoke('req_get', { url: 'https://api.github.com/repos/Grasscutters/Grasscutter/commits' }) - obj = JSON.parse(commits) + let commits: CommitResponse[] + if (grasscutterApiResponse?.commits == null) { + // If it didn't work, use official API + const response: string = await invoke('req_get', { url: 'https://api.github.com/repos/Grasscutters/Grasscutter/commits' }) + commits = JSON.parse(response) } else { - obj = obj.commits.gc_stable + commits = grasscutterApiResponse.commits.gc_stable } // Probably rate-limited - if (!Array.isArray(obj)) return + if (!Array.isArray(commits)) return // Get only first 5 - const commitsList = obj.slice(0, 10) - const commitsListHtml = commitsList.map((commit: any) => { + const commitsList = commits.slice(0, 10) + const commitsListHtml = commitsList.map((commitResponse: CommitResponse) => { return ( - - {commit.commit.author.name} - {commit.commit.message} + + {commitResponse.commit.author.name} + {commitResponse.commit.message} ) }) this.setState({ commitList: commitsListHtml, - news: commitsListHtml + news: <>{commitsListHtml} }) } @@ -83,12 +102,16 @@ export default class NewsSection extends React.Component { } async showNews() { - let news = + let news: JSX.Element | JSX.Element[] = switch(this.state.selected) { - case 'commits': - news = await this.showLatestCommits() + case 'commits': { + const commits = await this.showLatestCommits() + if (commits != null) { + news = commits + } break + } case 'latest_version': news = Latest version @@ -100,7 +123,7 @@ export default class NewsSection extends React.Component { } this.setState({ - news + news: <>{news} }) } diff --git a/src/utils/configuration.ts b/src/utils/configuration.ts index 5ce8863..65aa91e 100644 --- a/src/utils/configuration.ts +++ b/src/utils/configuration.ts @@ -45,16 +45,16 @@ export interface Configuration { debug_enabled: boolean } -export async function setConfigOption(key: string, value: any): Promise { - const config: any = await getConfig() +export async function setConfigOption(key: K, value: Configuration[K]): Promise { + const config = await getConfig() config[key] = value await saveConfig( config) } -export async function getConfigOption(key: string): Promise { - const config: any = await getConfig() - const defaults: any = defaultConfig +export async function getConfigOption(key: K): Promise { + const config = await getConfig() + const defaults = defaultConfig return config[key] || defaults[key] }