diff options
| author | Haishan <[email protected]> | 2020-10-31 18:18:04 +0800 |
|---|---|---|
| committer | Haishan <[email protected]> | 2020-11-01 17:42:52 +0800 |
| commit | ff1a39d04e53b428e34d46c55ecd6689189b5443 (patch) | |
| tree | 94a60abe3d28a1d729b877356bdd38d75ce655a5 /src | |
| parent | e62c9165481ef12ee2310dee1c32f890b3fe4b78 (diff) | |
chore: run ts-migrate
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/configs.ts | 3 | ||||
| -rw-r--r-- | src/api/connections.ts | 10 | ||||
| -rw-r--r-- | src/api/proxies.ts (renamed from src/api/proxies.js) | 0 | ||||
| -rw-r--r-- | src/api/traffic.ts (renamed from src/api/traffic.js) | 0 | ||||
| -rw-r--r-- | src/app.tsx (renamed from src/app.js) | 0 | ||||
| -rw-r--r-- | src/components/APIConfig.tsx | 2 | ||||
| -rw-r--r-- | src/components/APIDiscovery.tsx (renamed from src/components/APIDiscovery.js) | 2 | ||||
| -rw-r--r-- | src/components/BackendList.tsx | 1 | ||||
| -rw-r--r-- | src/components/Collapsible.tsx (renamed from src/components/Collapsible.js) | 2 | ||||
| -rw-r--r-- | src/components/Config.tsx (renamed from src/components/Config.js) | 6 | ||||
| -rw-r--r-- | src/components/ConnectionTable.tsx (renamed from src/components/ConnectionTable.js) | 0 | ||||
| -rw-r--r-- | src/components/Connections.tsx (renamed from src/components/Connections.js) | 66 | ||||
| -rw-r--r-- | src/components/ContentHeader.tsx (renamed from src/components/ContentHeader.js) | 12 | ||||
| -rw-r--r-- | src/components/ErrorBoundary.tsx (renamed from src/components/ErrorBoundary.js) | 19 | ||||
| -rw-r--r-- | src/components/ErrorBoundaryFallback.tsx (renamed from src/components/ErrorBoundaryFallback.js) | 12 | ||||
| -rw-r--r-- | src/components/Field.tsx (renamed from src/components/Field.js) | 19 | ||||
| -rw-r--r-- | src/components/Home.tsx (renamed from src/components/Home.js) | 0 | ||||
| -rw-r--r-- | src/components/Icon.tsx (renamed from src/components/Icon.js) | 17 | ||||
| -rw-r--r-- | src/components/Input.tsx (renamed from src/components/Input.js) | 20 | ||||
| -rw-r--r-- | src/components/Loading.tsx (renamed from src/components/Loading.js) | 12 | ||||
| -rw-r--r-- | src/components/Loading2.tsx (renamed from src/components/Loading2.js) | 0 | ||||
| -rw-r--r-- | src/components/LogSearch.ts (renamed from src/components/LogSearch.js) | 0 | ||||
| -rw-r--r-- | src/components/Logs.tsx (renamed from src/components/Logs.js) | 21 | ||||
| -rw-r--r-- | src/components/Modal.tsx (renamed from src/components/Modal.js) | 26 | ||||
| -rw-r--r-- | src/components/ModalCloseAllConnections.tsx (renamed from src/components/ModalCloseAllConnections.js) | 0 | ||||
| -rw-r--r-- | src/components/Rule.tsx (renamed from src/components/Rule.js) | 18 | ||||
| -rw-r--r-- | src/components/Rules.tsx (renamed from src/components/Rules.js) | 4 | ||||
| -rw-r--r-- | src/components/Search.tsx (renamed from src/components/Search.js) | 0 | ||||
| -rw-r--r-- | src/components/Selection.tsx (renamed from src/components/Selection.js) | 23 | ||||
| -rw-r--r-- | src/components/SideBar.tsx (renamed from src/components/SideBar.js) | 6 | ||||
| -rw-r--r-- | src/components/StateProvider.tsx (renamed from src/components/StateProvider.js) | 2 | ||||
| -rw-r--r-- | src/components/StyleGuide.tsx (renamed from src/components/StyleGuide.js) | 4 | ||||
| -rw-r--r-- | src/components/SvgGithub.tsx (renamed from src/components/SvgGithub.js) | 14 | ||||
| -rw-r--r-- | src/components/SvgYacd.tsx (renamed from src/components/SvgYacd.js) | 16 | ||||
| -rw-r--r-- | src/components/SwitchThemed.tsx (renamed from src/components/SwitchThemed.js) | 0 | ||||
| -rw-r--r-- | src/components/ToggleSwitch.tsx (renamed from src/components/ToggleSwitch.js) | 19 | ||||
| -rw-r--r-- | src/components/TrafficChart.tsx (renamed from src/components/TrafficChart.js) | 1 | ||||
| -rw-r--r-- | src/components/TrafficChartSample.tsx (renamed from src/components/TrafficChartSample.js) | 0 | ||||
| -rw-r--r-- | src/components/TrafficNow.tsx (renamed from src/components/TrafficNow.js) | 0 | ||||
| -rw-r--r-- | src/components/proxies/ProxyProvider.tsx | 4 | ||||
| -rw-r--r-- | src/components/proxies/Settings.tsx (renamed from src/components/proxies/Settings.js) | 0 | ||||
| -rw-r--r-- | src/components/proxies/hooks.tsx | 4 | ||||
| -rw-r--r-- | src/components/shared/BaseModal.tsx (renamed from src/components/shared/BaseModal.js) | 0 | ||||
| -rw-r--r-- | src/components/shared/Basic.tsx (renamed from src/components/shared/Basic.js) | 0 | ||||
| -rw-r--r-- | src/custom.d.ts | 3 | ||||
| -rw-r--r-- | src/hooks/basic.ts (renamed from src/hooks/basic.js) | 0 | ||||
| -rw-r--r-- | src/hooks/useLineChart.ts (renamed from src/hooks/useLineChart.js) | 1 | ||||
| -rw-r--r-- | src/hooks/useRemainingViewPortHeight.ts (renamed from src/hooks/useRemainingViewPortHeight.js) | 0 | ||||
| -rw-r--r-- | src/misc/chart.ts (renamed from src/misc/chart.js) | 0 | ||||
| -rw-r--r-- | src/misc/errors.ts (renamed from src/misc/errors.js) | 10 | ||||
| -rw-r--r-- | src/misc/pretty-bytes.js | 16 | ||||
| -rw-r--r-- | src/misc/pretty-bytes.ts | 13 | ||||
| -rw-r--r-- | src/misc/sentry.ts (renamed from src/misc/sentry.js) | 0 | ||||
| -rw-r--r-- | src/misc/shallowEqual.ts (renamed from src/misc/shallowEqual.js) | 0 | ||||
| -rw-r--r-- | src/misc/storage.ts (renamed from src/misc/storage.js) | 0 | ||||
| -rw-r--r-- | src/misc/utils.ts | 2 | ||||
| -rw-r--r-- | src/store/app.ts (renamed from src/store/app.js) | 59 | ||||
| -rw-r--r-- | src/store/configs.ts (renamed from src/store/configs.js) | 37 | ||||
| -rw-r--r-- | src/store/index.ts (renamed from src/store/index.js) | 0 | ||||
| -rw-r--r-- | src/store/logs.ts (renamed from src/store/logs.js) | 0 | ||||
| -rw-r--r-- | src/store/modals.ts (renamed from src/store/modals.js) | 0 | ||||
| -rw-r--r-- | src/store/proxies.tsx | 134 | ||||
| -rw-r--r-- | src/store/rules.ts (renamed from src/store/rules.js) | 0 | ||||
| -rw-r--r-- | src/store/types.ts | 91 |
64 files changed, 438 insertions, 293 deletions
diff --git a/src/api/configs.ts b/src/api/configs.ts index 4957e85..69b02d4 100644 --- a/src/api/configs.ts +++ b/src/api/configs.ts @@ -1,4 +1,5 @@ import { getURLAndInit } from 'src/misc/request-helper'; +import { ClashGeneralConfig } from 'src/store/types'; import { ClashAPIConfig } from 'src/types'; const endpoint = '/configs'; @@ -12,7 +13,7 @@ export async function fetchConfigs(apiConfig: ClashAPIConfig) { // req body // { Path: string } -type ClashConfigPartial = { 'socks-port'?: unknown }; +type ClashConfigPartial = Partial<ClashGeneralConfig>; function configsPatchWorkaround(o: ClashConfigPartial) { // backward compatibility for older clash using `socket-port` if ('socks-port' in o) { diff --git a/src/api/connections.ts b/src/api/connections.ts index 7608a41..d4ed58e 100644 --- a/src/api/connections.ts +++ b/src/api/connections.ts @@ -9,11 +9,13 @@ const subscribers = []; // see also https://github.com/Dreamacro/clash/blob/dev/constant/metadata.go#L41 type UUID = string; -type ConnectionItem = { +type ConnNetwork = 'tcp' | 'udp'; +type ConnType = 'HTTP' | 'HTTP Connect' | 'Socks5' | 'Redir' | 'Unknown'; +export type ConnectionItem = { id: UUID; metadata: { - network: 'tcp' | 'udp'; - type: 'HTTP' | 'HTTP Connect' | 'Socks5' | 'Redir' | 'Unknown'; + network: ConnNetwork; + type: ConnType; sourceIP: string; destinationIP: string; sourcePort: string; @@ -24,7 +26,7 @@ type ConnectionItem = { download: number; // e.g. "2019-11-30T22:48:13.416668+08:00", start: string; - chains: Array<string>; + chains: string[]; // e.g. 'Match', 'DomainKeyword' rule: string; }; diff --git a/src/api/proxies.js b/src/api/proxies.ts index 72e1c52..72e1c52 100644 --- a/src/api/proxies.js +++ b/src/api/proxies.ts diff --git a/src/api/traffic.js b/src/api/traffic.ts index e50ec5e..e50ec5e 100644 --- a/src/api/traffic.js +++ b/src/api/traffic.ts diff --git a/src/components/APIConfig.tsx b/src/components/APIConfig.tsx index 01c1b43..54e6e58 100644 --- a/src/components/APIConfig.tsx +++ b/src/components/APIConfig.tsx @@ -80,6 +80,7 @@ function APIConfig({ dispatch }) { <div className={s0.hostnamePort}> <Field id="baseURL" + // @ts-expect-error ts-migrate(2322) FIXME: Type '{ id: string; name: string; label: string; t... Remove this comment to see the full error message name="baseURL" label="API Base URL" type="text" @@ -88,6 +89,7 @@ function APIConfig({ dispatch }) { /> <Field id="secret" + // @ts-expect-error ts-migrate(2322) FIXME: Type '{ id: string; name: string; label: string; v... Remove this comment to see the full error message name="secret" label="Secret(optional)" value={secret} diff --git a/src/components/APIDiscovery.js b/src/components/APIDiscovery.tsx index 550fae0..97f3538 100644 --- a/src/components/APIDiscovery.js +++ b/src/components/APIDiscovery.tsx @@ -15,6 +15,7 @@ function APIDiscovery({ dispatch, apiConfig, modals }) { if (!window.fetch) { const { detail } = errors[DOES_NOT_SUPPORT_FETCH]; const err = new Error(detail); + // @ts-expect-error ts-migrate(2339) FIXME: Property 'code' does not exist on type 'Error'. err.code = DOES_NOT_SUPPORT_FETCH; throw err; } @@ -31,6 +32,7 @@ function APIDiscovery({ dispatch, apiConfig, modals }) { isOpen={modals.apiConfig} className={s0.content} overlayClassName={s0.overlay} + // @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: Element; isOpen: any; className:... Remove this comment to see the full error message shouldCloseOnOverlayClick={false} shouldCloseOnEsc={false} onRequestClose={closeApiConfigModal} diff --git a/src/components/BackendList.tsx b/src/components/BackendList.tsx index a0c993f..4bfb64c 100644 --- a/src/components/BackendList.tsx +++ b/src/components/BackendList.tsx @@ -114,6 +114,7 @@ function Item({ <> <span className={s.secret}>{show ? secret : '***'}</span> + {/* @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean | (() => void)' is not assignable to... Remove this comment to see the full error message */} <Button onClick={toggle} className={s.eye}> <Icon size={20} /> </Button> diff --git a/src/components/Collapsible.js b/src/components/Collapsible.tsx index d8d9313..e9a1ee8 100644 --- a/src/components/Collapsible.js +++ b/src/components/Collapsible.tsx @@ -50,10 +50,12 @@ const variantsCollpapsibleChildContainer = { }, }; +// @ts-expect-error ts-migrate(2339) FIXME: Property 'isOpen' does not exist on type '{ childr... Remove this comment to see the full error message const Collapsible = memo(({ children, isOpen }) => { const module = framerMotionResouce.read(); const motion = module.motion; const previous = usePrevious(isOpen); + // @ts-expect-error ts-migrate(2339) FIXME: Property 'height' does not exist on type 'MutableR... Remove this comment to see the full error message const [refToMeature, { height }] = useMeasure(); return ( <div> diff --git a/src/components/Config.js b/src/components/Config.tsx index f14f7d9..16fc6b1 100644 --- a/src/components/Config.js +++ b/src/components/Config.tsx @@ -119,11 +119,11 @@ function ConfigImpl({ ); const handleSwitchOnChange = useCallback( - (checked) => { + (checked: boolean) => { const name = 'allow-lan'; const value = checked; setConfigState(name, value); - dispatch(updateConfigs(apiConfig, { [name]: value })); + dispatch(updateConfigs(apiConfig, { 'allow-lan': value })); }, [apiConfig, dispatch, setConfigState] ); @@ -200,6 +200,7 @@ function ConfigImpl({ name={f.key} value={configState[f.key]} onChange={handleInputOnChange} + // @ts-expect-error ts-migrate(2322) FIXME: Type '{ name: string; value: any; onChange: (e: an... Remove this comment to see the full error message onBlur={handleInputOnBlur} /> </div> @@ -267,6 +268,7 @@ function ConfigImpl({ ); } +// @ts-expect-error ts-migrate(2339) FIXME: Property 'propTypes' does not exist on type '(prop... Remove this comment to see the full error message Config.propTypes = { configs: PropTypes.object, }; diff --git a/src/components/ConnectionTable.js b/src/components/ConnectionTable.tsx index 6d9f86e..6d9f86e 100644 --- a/src/components/ConnectionTable.js +++ b/src/components/ConnectionTable.tsx diff --git a/src/components/Connections.js b/src/components/Connections.tsx index e5c8110..078d32e 100644 --- a/src/components/Connections.js +++ b/src/components/Connections.tsx @@ -3,6 +3,8 @@ import './Connections.css'; import React from 'react'; import { Pause, Play, X as IconClose } from 'react-feather'; import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; +import { ConnectionItem } from 'src/api/connections'; +import { State } from 'src/store/types'; import * as connAPI from '../api/connections'; import useRemainingViewPortHeight from '../hooks/useRemainingViewPortHeight'; @@ -19,7 +21,7 @@ const { useEffect, useState, useRef, useCallback } = React; const paddingBottom = 30; -function arrayToIdKv(items) { +function arrayToIdKv<T extends { id: string }>(items: T[]) { const o = {}; for (let i = 0; i < items.length; i++) { const item = items[i]; @@ -28,9 +30,30 @@ function arrayToIdKv(items) { return o; } -function filterConns(conns, keyword) { - const hasSubstring = (s, pat) => s.toLowerCase().includes(pat.toLowerCase()); +type FormattedConn = { + id: string; + upload: number; + download: number; + start: number; + chains: string; + rule: string; + destinationPort: string; + destinationIP: string; + sourceIP: string; + sourcePort: string; + source: string; + host: string; + type: string; + network: string; + downloadSpeedCurr?: number; + uploadSpeedCurr?: number; +}; +function hasSubstring(s: string, pat: string) { + return s.toLowerCase().includes(pat.toLowerCase()); +} + +function filterConns(conns: FormattedConn[], keyword: string) { return !keyword ? conns : conns.filter((conn) => @@ -47,10 +70,13 @@ function filterConns(conns, keyword) { ); } -function formatConnectionDataItem(i, prevKv, now) { +function formatConnectionDataItem( + i: ConnectionItem, + prevKv: Record<string, { upload: number; download: number }>, + now: number +): FormattedConn { const { id, metadata, upload, download, start, chains, rule } = i; - // eslint-disable-next-line prefer-const - let { + const { host, destinationPort, destinationIP, @@ -60,27 +86,27 @@ function formatConnectionDataItem(i, prevKv, now) { sourcePort, } = metadata; // host could be an empty string if it's direct IP connection - if (host === '') host = destinationIP; - + let host2 = host; + if (host2 === '') host2 = destinationIP; + const prev = prevKv[id]; const ret = { id, upload, download, - start: now - new Date(start), + start: now - new Date(start).valueOf(), chains: chains.reverse().join(' / '), rule, ...metadata, - host: `${host}:${destinationPort}`, + host: `${host2}:${destinationPort}`, type: `${type}(${network})`, source: `${sourceIP}:${sourcePort}`, + downloadSpeedCurr: download - (prev ? prev.download : 0), + uploadSpeedCurr: upload - (prev ? prev.upload : 0), }; - const prev = prevKv[id]; - ret.downloadSpeedCurr = download - (prev ? prev.download : 0); - ret.uploadSpeedCurr = upload - (prev ? prev.upload : 0); return ret; } -function renderTableOrPlaceholder(conns) { +function renderTableOrPlaceholder(conns: FormattedConn[]) { return conns.length > 0 ? ( <ConnectionTable data={conns} /> ) : ( @@ -119,13 +145,13 @@ function Conn({ apiConfig }) { const read = useCallback( ({ connections }) => { const prevConnsKv = arrayToIdKv(prevConnsRef.current); - const now = new Date(); - const x = connections.map((c) => + const now = Date.now(); + const x = connections.map((c: ConnectionItem) => formatConnectionDataItem(c, prevConnsKv, now) ); const closed = []; for (const c of prevConnsRef.current) { - const idx = x.findIndex((conn) => conn.id === c.id); + const idx = x.findIndex((conn: ConnectionItem) => conn.id === c.id); if (idx < 0) closed.push(c); } setClosedConns((prev) => { @@ -165,12 +191,14 @@ function Conn({ apiConfig }) { <Tab> <span>Active</span> <span className={s.connQty}> + {/* @ts-expect-error ts-migrate(2786) FIXME: 'ConnQty' cannot be used as a JSX component. */} <ConnQty qty={filteredConns.length} /> </span> </Tab> <Tab> <span>Closed</span> <span className={s.connQty}> + {/* @ts-expect-error ts-migrate(2786) FIXME: 'ConnQty' cannot be used as a JSX component. */} <ConnQty qty={filteredClosedConns.length} /> </span> </Tab> @@ -187,11 +215,13 @@ function Conn({ apiConfig }) { </div> </div> <div + // @ts-expect-error ts-migrate(2322) FIXME: Type 'number | MutableRefObject<any>' is not assig... Remove this comment to see the full error message ref={refContainer} style={{ padding: 30, paddingBottom, paddingTop: 0 }} > <div style={{ + // @ts-expect-error ts-migrate(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message height: containerHeight - paddingBottom, overflow: 'auto', }} @@ -234,7 +264,7 @@ function Conn({ apiConfig }) { ); } -const mapState = (s) => ({ +const mapState = (s: State) => ({ apiConfig: getClashAPIConfig(s), }); diff --git a/src/components/ContentHeader.js b/src/components/ContentHeader.tsx index 44df5a8..148a071 100644 --- a/src/components/ContentHeader.js +++ b/src/components/ContentHeader.tsx @@ -1,9 +1,13 @@ -import PropTypes from 'prop-types'; + import React from 'react'; import s0 from './ContentHeader.module.css'; -function ContentHeader({ title }) { +type Props = { + title: string; +}; + +function ContentHeader({ title }: Props) { return ( <div className={s0.root}> <h1 className={s0.h1}>{title}</h1> @@ -11,8 +15,4 @@ function ContentHeader({ title }) { ); } -ContentHeader.propTypes = { - title: PropTypes.string.isRequired, -}; - export default React.memo(ContentHeader); diff --git a/src/components/ErrorBoundary.js b/src/components/ErrorBoundary.tsx index ff49e1e..38d90e2 100644 --- a/src/components/ErrorBoundary.js +++ b/src/components/ErrorBoundary.tsx @@ -1,18 +1,21 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; +import * as React from 'react'; // import { getSentry } from '../misc/sentry'; -import { deriveMessageFromError } from '../misc/errors'; +import { deriveMessageFromError,Err } from '../misc/errors'; import ErrorBoundaryFallback from './ErrorBoundaryFallback'; -class ErrorBoundary extends Component { - static propTypes = { - children: PropTypes.node, - }; +type Props = { + children: React.ReactNode; +}; +type State = { + error?: Err; +}; + +class ErrorBoundary extends React.Component<Props, State> { state = { error: null }; - static getDerivedStateFromError(error) { + static getDerivedStateFromError(error: Err) { return { error }; } diff --git a/src/components/ErrorBoundaryFallback.js b/src/components/ErrorBoundaryFallback.tsx index b03428e..bbaf2d7 100644 --- a/src/components/ErrorBoundaryFallback.js +++ b/src/components/ErrorBoundaryFallback.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React from 'react'; import s0 from './ErrorBoundaryFallback.module.css'; @@ -6,7 +5,12 @@ import SvgGithub from './SvgGithub'; import SvgYacd from './SvgYacd'; const yacdRepoIssueUrl = 'https://github.com/haishanh/yacd/issues'; -function ErrorBoundaryFallback({ message, detail }) { +type Props = { + message?: string; + detail?: string; +}; + +function ErrorBoundaryFallback({ message, detail }: Props) { return ( <div className={s0.root}> <div className={s0.yacd}> @@ -24,8 +28,4 @@ function ErrorBoundaryFallback({ message, detail }) { ); } -ErrorBoundaryFallback.propTypes = { - message: PropTypes.string, -}; - export default ErrorBoundaryFallback; diff --git a/src/components/Field.js b/src/components/Field.tsx index 81bd372..8e2f7e3 100644 --- a/src/components/Field.js +++ b/src/components/Field.tsx @@ -1,12 +1,19 @@ import cx from 'clsx'; -import PropTypes from 'prop-types'; import React from 'react'; import s from './Field.module.css'; const { useCallback } = React; -export default function Field({ id, label, value, onChange, ...props }) { +type Props = { + value?: string | number; + type?: 'text' | 'number'; + onChange?: (...args: any[]) => any; + id?: string; + label?: string; +}; + +export default function Field({ id, label, value, onChange, ...props }: Props) { const valueOnChange = useCallback((e) => onChange(e), [onChange]); const labelClassName = cx({ [s.floatAbove]: typeof value === 'string' && value !== '', @@ -20,11 +27,3 @@ export default function Field({ id, label, value, onChange, ...props }) { </div> ); } - -Field.propTypes = { - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - type: PropTypes.oneOf(['text', 'number']), - onChange: PropTypes.func, - id: PropTypes.string, - label: PropTypes.string, -}; diff --git a/src/components/Home.js b/src/components/Home.tsx index 532379b..532379b 100644 --- a/src/components/Home.js +++ b/src/components/Home.tsx diff --git a/src/components/Icon.js b/src/components/Icon.tsx index 2ad162c..9922e58 100644 --- a/src/components/Icon.js +++ b/src/components/Icon.tsx @@ -1,8 +1,14 @@ import cx from 'clsx'; -import PropTypes from 'prop-types'; import React from 'react'; -const Icon = ({ id, width = 20, height = 20, className, ...props }) => { +type Props = { + id: string; + width?: number; + height?: number; + className?: string; +}; + +const Icon = ({ id, width = 20, height = 20, className, ...props }: Props) => { const c = cx('icon', id, className); const href = '#' + id; return ( @@ -12,11 +18,4 @@ const Icon = ({ id, width = 20, height = 20, className, ...props }) => { ); }; -Icon.propTypes = { - id: PropTypes.string.isRequired, - width: PropTypes.number, - height: PropTypes.number, - className: PropTypes.string, -}; - export default React.memo(Icon); diff --git a/src/components/Input.js b/src/components/Input.tsx index efdb6ca..8a8c65a 100644 --- a/src/components/Input.js +++ b/src/components/Input.tsx @@ -1,11 +1,19 @@ -import PropTypes from 'prop-types'; + import React from 'react'; import s0 from './Input.module.css'; const { useState, useRef, useEffect, useCallback } = React; -export default function Input(props) { +type InputProps = { + value?: string | number; + type?: string; + onChange?: (...args: any[]) => any; + name?: string; + placeholder?: string; +}; + +export default function Input(props: InputProps) { return <input className={s0.input} {...props} />; } @@ -32,11 +40,3 @@ export function SelfControlledInput({ value, ...restProps }) { /> ); } - -Input.propTypes = { - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - type: PropTypes.string, - onChange: PropTypes.func, - name: PropTypes.string, - placeholder: PropTypes.string, -}; diff --git a/src/components/Loading.js b/src/components/Loading.tsx index 3547d03..7f83416 100644 --- a/src/components/Loading.js +++ b/src/components/Loading.tsx @@ -1,9 +1,13 @@ -import PropTypes from 'prop-types'; + import React from 'react'; import s0 from './Loading.module.css'; -const Loading = ({ height }) => { +type Props = { + height?: string; +}; + +const Loading = ({ height }: Props) => { const style = height ? { height } : {}; return ( <div className={s0.loading} style={style}> @@ -12,8 +16,4 @@ const Loading = ({ height }) => { ); }; -Loading.propTypes = { - height: PropTypes.string, -}; - export default Loading; diff --git a/src/components/Loading2.js b/src/components/Loading2.tsx index edb2656..edb2656 100644 --- a/src/components/Loading2.js +++ b/src/components/Loading2.tsx diff --git a/src/components/LogSearch.js b/src/components/LogSearch.ts index 9c7879f..9c7879f 100644 --- a/src/components/LogSearch.js +++ b/src/components/LogSearch.ts diff --git a/src/components/Logs.js b/src/components/Logs.tsx index 4ba59b9..d563e77 100644 --- a/src/components/Logs.js +++ b/src/components/Logs.tsx @@ -1,5 +1,4 @@ import cx from 'clsx'; -import PropTypes from 'prop-types'; import React from 'react'; import { areEqual, FixedSizeList as List } from 'react-window'; @@ -26,7 +25,14 @@ const colors = { error: '#c11c1c', }; -function LogLine({ time, even, payload, type }) { +type LogLineProps = { + time?: string; + even?: boolean; + payload?: string; + type?: string; +}; + +function LogLine({ time, even, payload, type }: LogLineProps) { const className = cx({ even }, s0.log); return ( <div className={className}> @@ -41,18 +47,12 @@ function LogLine({ time, even, payload, type }) { ); } -LogLine.propTypes = { - time: PropTypes.string, - even: PropTypes.bool, - payload: PropTypes.string, - type: PropTypes.string, -}; - function itemKey(index, data) { const item = data[index]; return item.id; } +// @ts-expect-error ts-migrate(2339) FIXME: Property 'index' does not exist on type '{ childre... Remove this comment to see the full error message const Row = memo(({ index, style, data }) => { const r = data[index]; return ( @@ -78,10 +78,12 @@ function Logs({ dispatch, logLevel, apiConfig, logs }) { <div> <ContentHeader title="Logs" /> <LogSearch /> + {/* @ts-expect-error ts-migrate(2322) FIXME: Type 'number | MutableRefObject<any>' is not assig... Remove this comment to see the full error message */} <div ref={refLogsContainer} style={{ paddingBottom }}> {logs.length === 0 ? ( <div className={s0.logPlaceholder} + // @ts-expect-error ts-migrate(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message style={{ height: containerHeight - paddingBottom }} > <div className={s0.logPlaceholderIcon}> @@ -92,6 +94,7 @@ function Logs({ dispatch, logLevel, apiConfig, logs }) { ) : ( <div className={s0.logsWrapper}> <List + // @ts-expect-error ts-migrate(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message height={containerHeight - paddingBottom} width="100%" itemCount={logs.length} diff --git a/src/components/Modal.js b/src/components/Modal.tsx index 2144eb5..885b350 100644 --- a/src/components/Modal.js +++ b/src/components/Modal.tsx @@ -1,18 +1,18 @@ import cx from 'clsx'; -import PropTypes from 'prop-types'; import React from 'react'; import Modal from 'react-modal'; import s0 from './Modal.module.css'; -function ModalAPIConfig({ - isOpen, - onRequestClose, - className, - overlayClassName, - children, - ...otherProps -}) { +type Props = { + isOpen: boolean; + onRequestClose: (...args: any[]) => any; + children: React.ReactNode; + className?: string; + overlayClassName?: string; +}; + +function ModalAPIConfig({ isOpen, onRequestClose, className, overlayClassName, children, ...otherProps }: Props) { const contentCls = cx(className, s0.content); const overlayCls = cx(overlayClassName, s0.overlay); return ( @@ -28,12 +28,4 @@ function ModalAPIConfig({ ); } -ModalAPIConfig.propTypes = { - isOpen: PropTypes.bool.isRequired, - onRequestClose: PropTypes.func.isRequired, - children: PropTypes.node.isRequired, - className: PropTypes.string, - overlayClassName: PropTypes.string, -}; - export default React.memo(ModalAPIConfig); diff --git a/src/components/ModalCloseAllConnections.js b/src/components/ModalCloseAllConnections.tsx index ce567b8..ce567b8 100644 --- a/src/components/ModalCloseAllConnections.js +++ b/src/components/ModalCloseAllConnections.tsx diff --git a/src/components/Rule.js b/src/components/Rule.tsx index da21e2f..cf5339d 100644 --- a/src/components/Rule.js +++ b/src/components/Rule.tsx @@ -1,4 +1,4 @@ -import PropTypes from 'prop-types'; + import React from 'react'; import s0 from './Rule.module.css'; @@ -17,7 +17,14 @@ function getStyleFor({ proxy }) { return { color }; } -function Rule({ type, payload, proxy, id }) { +type Props = { + id?: number; + type?: string; + payload?: string; + proxy?: string; +}; + +function Rule({ type, payload, proxy, id }: Props) { const styleProxy = getStyleFor({ proxy }); return ( <div className={s0.rule}> @@ -33,11 +40,4 @@ function Rule({ type, payload, proxy, id }) { ); } -Rule.propTypes = { - id: PropTypes.number, - type: PropTypes.string, - payload: PropTypes.string, - proxy: PropTypes.string, -}; - export default Rule; diff --git a/src/components/Rules.js b/src/components/Rules.tsx index 949e5e9..dab479c 100644 --- a/src/components/Rules.js +++ b/src/components/Rules.tsx @@ -43,6 +43,7 @@ function getItemSizeFactory({ provider }) { }; } +// @ts-expect-error ts-migrate(2339) FIXME: Property 'index' does not exist on type '{ childre... Remove this comment to see the full error message const Row = memo(({ index, style, data }) => { const { rules, provider, apiConfig } = data; const providerQty = provider.names.length; @@ -110,6 +111,7 @@ function Rules({ apiConfig }) { const { rules, provider } = useRuleAndProvider(apiConfig); const invalidateQueries = useInvalidateQueries(); + // @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ rules: RuleItem[]; provider: {... Remove this comment to see the full error message const getItemSize = getItemSizeFactory({ rules, provider }); return ( @@ -118,8 +120,10 @@ function Rules({ apiConfig }) { <ContentHeader title="Rules" /> <TextFilter /> </div> + {/* @ts-expect-error ts-migrate(2322) FIXME: Type 'number | MutableRefObject<any>' is not assig... Remove this comment to see the full error message */} <div ref={refRulesContainer} style={{ paddingBottom }}> <VariableSizeList + // @ts-expect-error ts-migrate(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message height={containerHeight - paddingBottom} width="100%" itemCount={rules.length + provider.names.length} diff --git a/src/components/Search.js b/src/components/Search.tsx index 2d8c754..2d8c754 100644 --- a/src/components/Search.js +++ b/src/components/Search.tsx diff --git a/src/components/Selection.js b/src/components/Selection.tsx index 764e7b3..9bcb4c8 100644 --- a/src/components/Selection.js +++ b/src/components/Selection.tsx @@ -1,15 +1,16 @@ import cx from 'clsx'; -import { array, func, number } from 'prop-types'; import React from 'react'; import s from './Selection.module.css'; -export default function Selection({ - OptionComponent, - optionPropsList, - selectedIndex, - onChange, -}) { +type SelectionProps = { + OptionComponent?: (...args: any[]) => any; + optionPropsList?: any[]; + selectedIndex?: number; + onChange?: (...args: any[]) => any; +}; + +export default function Selection({ OptionComponent, optionPropsList, selectedIndex, onChange, }: SelectionProps) { return ( <div className={s.root}> {optionPropsList.map((props, idx) => { @@ -35,14 +36,8 @@ export default function Selection({ ); } -Selection.propTypes = { - OptionComponent: func, - optionPropsList: array, - selectedIndex: number, - onChange: func, -}; - // for test +// @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value. export function Option({ title }) { // eslint-disable-next-line no-undef if (__DEV__) { diff --git a/src/components/SideBar.js b/src/components/SideBar.tsx index 756af06..6bf58b5 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.tsx @@ -40,9 +40,13 @@ const icons = { }; const SideBarRow = React.memo(function SideBarRow({ + // @ts-expect-error ts-migrate(2339) FIXME: Property 'isActive' does not exist on type '{ chil... Remove this comment to see the full error message isActive, + // @ts-expect-error ts-migrate(2339) FIXME: Property 'to' does not exist on type '{ children?:... Remove this comment to see the full error message to, + // @ts-expect-error ts-migrate(2339) FIXME: Property 'iconId' does not exist on type '{ childr... Remove this comment to see the full error message iconId, + // @ts-expect-error ts-migrate(2339) FIXME: Property 'labelText' does not exist on type '{ chi... Remove this comment to see the full error message labelText, }) { const Comp = icons[iconId]; @@ -55,6 +59,7 @@ const SideBarRow = React.memo(function SideBarRow({ ); }); +// @ts-expect-error ts-migrate(2339) FIXME: Property 'propTypes' does not exist on type 'Named... Remove this comment to see the full error message SideBarRow.propTypes = { isActive: PropTypes.bool.isRequired, to: PropTypes.string.isRequired, @@ -107,6 +112,7 @@ function SideBar({ dispatch, theme }) { {pages.map(({ to, iconId, labelText }) => ( <SideBarRow key={to} + // @ts-expect-error ts-migrate(2322) FIXME: Type '{ key: string; to: string; isActive: boolean... Remove this comment to see the full error message to={to} isActive={location.pathname === to} iconId={iconId} diff --git a/src/components/StateProvider.js b/src/components/StateProvider.tsx index e905d98..beb7ce4 100644 --- a/src/components/StateProvider.js +++ b/src/components/StateProvider.tsx @@ -42,6 +42,7 @@ export default function Provider({ initialState, actions = {}, children }) { const getState = useCallback(() => stateRef.current, []); useEffect(() => { if (process.env.NODE_ENV === 'development') { + // @ts-expect-error ts-migrate(2339) FIXME: Property 'getState2' does not exist on type 'Windo... Remove this comment to see the full error message window.getState2 = getState; } }, [getState]); @@ -94,6 +95,7 @@ export function connect(mapStateToProps) { // steal from https://github.com/reduxjs/redux/blob/master/src/bindActionCreators.ts function bindAction(action, dispatch) { return function (...args) { + // @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message return dispatch(action.apply(this, args)); }; } diff --git a/src/components/StyleGuide.js b/src/components/StyleGuide.tsx index 5979ee5..99c8bb0 100644 --- a/src/components/StyleGuide.js +++ b/src/components/StyleGuide.tsx @@ -51,12 +51,15 @@ class StyleGuide extends PureComponent { render() { return ( <div> + {/* @ts-expect-error ts-migrate(2741) FIXME: Property 'style' is missing in type '{ children: E... Remove this comment to see the full error message */} <Pane> <SwitchExample /> </Pane> + {/* @ts-expect-error ts-migrate(2741) FIXME: Property 'style' is missing in type '{ children: E... Remove this comment to see the full error message */} <Pane> <Input /> </Pane> + {/* @ts-expect-error ts-migrate(2741) FIXME: Property 'style' is missing in type '{ children: E... Remove this comment to see the full error message */} <Pane> <ToggleSwitch name="test" @@ -65,6 +68,7 @@ class StyleGuide extends PureComponent { onChange={noop} /> </Pane> + {/* @ts-expect-error ts-migrate(2741) FIXME: Property 'style' is missing in type '{ children: E... Remove this comment to see the full error message */} <Pane> <Button text="Test Lxatency" start={<Zap size={16} />} /> <Button text="Test Lxatency" start={<Zap size={16} />} isLoading /> diff --git a/src/components/SvgGithub.js b/src/components/SvgGithub.tsx index bc79cd3..b400b55 100644 --- a/src/components/SvgGithub.js +++ b/src/components/SvgGithub.tsx @@ -1,7 +1,12 @@ -import PropTypes from 'prop-types'; + import React from 'react'; -export default function SvgGithub({ width = 24, height = 24 } = {}) { +type Props = { + width?: number; + height?: number; +}; + +export default function SvgGithub({ width = 24, height = 24 }: Props = {}) { return ( <svg xmlns="http://www.w3.org/2000/svg" @@ -18,8 +23,3 @@ export default function SvgGithub({ width = 24, height = 24 } = {}) { </svg> ); } - -SvgGithub.propTypes = { - width: PropTypes.number, - height: PropTypes.number, -}; diff --git a/src/components/SvgYacd.js b/src/components/SvgYacd.tsx index 0dcd36c..2aa5cc1 100644 --- a/src/components/SvgYacd.js +++ b/src/components/SvgYacd.tsx @@ -1,16 +1,23 @@ import cx from 'clsx'; -import PropTypes from 'prop-types'; import React from 'react'; import s from './SvgYacd.module.css'; +type Props = { + width?: number; + height?: number; + animate?: boolean; + c0?: string; + c1?: string; +}; + function SvgYacd({ width = 320, height = 320, animate = false, c0 = 'currentColor', c1 = '#eee', -}) { +}: Props) { const faceClasName = cx({ [s.path]: animate }); return ( <svg @@ -40,9 +47,4 @@ function SvgYacd({ ); } -SvgYacd.propTypes = { - width: PropTypes.number, - height: PropTypes.number, -}; - export default SvgYacd; diff --git a/src/components/SwitchThemed.js b/src/components/SwitchThemed.tsx index 5c528f4..5c528f4 100644 --- a/src/components/SwitchThemed.js +++ b/src/components/SwitchThemed.tsx diff --git a/src/components/ToggleSwitch.js b/src/components/ToggleSwitch.tsx index 03af15f..62f3418 100644 --- a/src/components/ToggleSwitch.js +++ b/src/components/ToggleSwitch.tsx @@ -1,15 +1,23 @@ -import PropTypes from 'prop-types'; + import React, { useCallback, useMemo } from 'react'; import s0 from './ToggleSwitch.module.css'; -function ToggleSwitch({ options, value, name, onChange }) { +type Props = { + options?: any[]; + value?: string; + name?: string; + onChange?: (...args: any[]) => any; +}; + +function ToggleSwitch({ options, value, name, onChange }: Props) { const idxSelected = useMemo( () => options.map((o) => o.value).indexOf(value), [options, value] ); const getPortionPercentage = useCallback( + // @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value. (idx) => { const w = Math.floor(100 / options.length); if (idx === options.length - 1) { @@ -59,11 +67,4 @@ function ToggleSwitch({ options, value, name, onChange }) { ); } -ToggleSwitch.propTypes = { - options: PropTypes.array, - value: PropTypes.string, - name: PropTypes.string, - onChange: PropTypes.func, -}; - export default React.memo(ToggleSwitch); diff --git a/src/components/TrafficChart.js b/src/components/TrafficChart.tsx index bcfd4dc..5fcdf7d 100644 --- a/src/components/TrafficChart.js +++ b/src/components/TrafficChart.tsx @@ -50,6 +50,7 @@ function TrafficChart({ apiConfig, selectedChartStyleIndex }) { useLineChart(Chart, 'trafficChart', data, traffic); return ( + // @ts-expect-error ts-migrate(2322) FIXME: Type '{ position: string; maxWidth: number; }' is ... Remove this comment to see the full error message <div style={chartWrapperStyle}> <canvas id="trafficChart" /> </div> diff --git a/src/components/TrafficChartSample.js b/src/components/TrafficChartSample.tsx index 0723505..0723505 100644 --- a/src/components/TrafficChartSample.js +++ b/src/components/TrafficChartSample.tsx diff --git a/src/components/TrafficNow.js b/src/components/TrafficNow.tsx index cfab65b..cfab65b 100644 --- a/src/components/TrafficNow.js +++ b/src/components/TrafficNow.tsx diff --git a/src/components/proxies/ProxyProvider.tsx b/src/components/proxies/ProxyProvider.tsx index fd9f942..de0a94f 100644 --- a/src/components/proxies/ProxyProvider.tsx +++ b/src/components/proxies/ProxyProvider.tsx @@ -1,6 +1,7 @@ import { formatDistance } from 'date-fns'; import * as React from 'react'; import { RotateCw, Zap } from 'react-feather'; +import { DelayMapping } from 'src/store/types'; import { framerMotionResouce } from '../../misc/motion'; import { @@ -10,7 +11,6 @@ import { getProxySortBy, } from '../../store/app'; import { - DelayMapping, getDelay, healthcheckProviderByName, updateProviderByName, @@ -89,6 +89,7 @@ function ProxyProviderImpl({ <div className={s.updatedAt}> <small>Updated {timeAgo} ago</small> </div> + {/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: Element[]; isOpen: boolean; }' i... Remove this comment to see the full error message */} <Collapsible isOpen={isOpen}> <ProxyList all={proxies} /> <div className={s.actionFooter}> @@ -101,6 +102,7 @@ function ProxyProviderImpl({ /> </div> </Collapsible> + {/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: Element; isOpen: boolean; }' is ... Remove this comment to see the full error message */} <Collapsible isOpen={!isOpen}> <ProxyListSummaryView all={proxies} /> </Collapsible> diff --git a/src/components/proxies/Settings.js b/src/components/proxies/Settings.tsx index bb859ac..bb859ac 100644 --- a/src/components/proxies/Settings.js +++ b/src/components/proxies/Settings.tsx diff --git a/src/components/proxies/hooks.tsx b/src/components/proxies/hooks.tsx index 7536633..861c0e5 100644 --- a/src/components/proxies/hooks.tsx +++ b/src/components/proxies/hooks.tsx @@ -1,14 +1,12 @@ import * as React from 'react'; import { useRecoilState } from 'recoil'; +import { DelayMapping, ProxiesMapping, ProxyItem } from 'src/store/types'; import { // types - DelayMapping, NonProxyTypes, - ProxiesMapping, // atom proxyFilterText, - ProxyItem, } from '../../store/proxies'; const { useMemo } = React; diff --git a/src/components/shared/BaseModal.js b/src/components/shared/BaseModal.tsx index dcd0b57..dcd0b57 100644 --- a/src/components/shared/BaseModal.js +++ b/src/components/shared/BaseModal.tsx diff --git a/src/components/shared/Basic.js b/src/components/shared/Basic.tsx index dbd1bc7..dbd1bc7 100644 --- a/src/components/shared/Basic.js +++ b/src/components/shared/Basic.tsx diff --git a/src/custom.d.ts b/src/custom.d.ts index e60e225..11b9c6c 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -1,3 +1,6 @@ +/// <reference types="react/experimental" /> +/// <reference types="react-dom/experimental" /> + // for css modules declare module '*.module.css' { const classes: { [key: string]: string }; diff --git a/src/hooks/basic.js b/src/hooks/basic.ts index c8eddbc..c8eddbc 100644 --- a/src/hooks/basic.js +++ b/src/hooks/basic.ts diff --git a/src/hooks/useLineChart.js b/src/hooks/useLineChart.ts index 8d449e0..3bfd7d7 100644 --- a/src/hooks/useLineChart.js +++ b/src/hooks/useLineChart.ts @@ -13,6 +13,7 @@ export default function useLineChart( extraChartOptions = {} ) { useEffect(() => { + // @ts-expect-error ts-migrate(2339) FIXME: Property 'getContext' does not exist on type 'HTML... Remove this comment to see the full error message const ctx = document.getElementById(elementId).getContext('2d'); const c = new Chart(ctx, { type: 'line', diff --git a/src/hooks/useRemainingViewPortHeight.js b/src/hooks/useRemainingViewPortHeight.ts index e8346d8..e8346d8 100644 --- a/src/hooks/useRemainingViewPortHeight.js +++ b/src/hooks/useRemainingViewPortHeight.ts diff --git a/src/misc/chart.js b/src/misc/chart.ts index 9e2c459..9e2c459 100644 --- a/src/misc/chart.js +++ b/src/misc/chart.ts diff --git a/src/misc/errors.js b/src/misc/errors.ts index 1891aa0..1bc369a 100644 --- a/src/misc/errors.js +++ b/src/misc/errors.ts @@ -3,14 +3,16 @@ export const DOES_NOT_SUPPORT_FETCH = 0; export const errors = { [DOES_NOT_SUPPORT_FETCH]: { message: 'Browser not supported!', - detail: 'This browser does not support "fetch", please choose another one.' + detail: 'This browser does not support "fetch", please choose another one.', }, default: { - message: 'Oops, something went wrong!' - } + message: 'Oops, something went wrong!', + }, }; -export function deriveMessageFromError(err) { +export type Err = { code: number }; + +export function deriveMessageFromError(err: Err) { const { code } = err; if (typeof code === 'number') { return errors[code]; diff --git a/src/misc/pretty-bytes.js b/src/misc/pretty-bytes.js deleted file mode 100644 index e33b34e..0000000 --- a/src/misc/pretty-bytes.js +++ /dev/null @@ -1,16 +0,0 @@ -// steal from https://github.com/sindresorhus/pretty-bytes/blob/master/index.js - -const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - -export default number => { - if (number < 1000) { - return number + ' B'; - } - const exponent = Math.min( - Math.floor(Math.log10(number) / 3), - UNITS.length - 1 - ); - number = Number((number / Math.pow(1000, exponent)).toPrecision(3)); - const unit = UNITS[exponent]; - return number + ' ' + unit; -}; diff --git a/src/misc/pretty-bytes.ts b/src/misc/pretty-bytes.ts new file mode 100644 index 0000000..68b6776 --- /dev/null +++ b/src/misc/pretty-bytes.ts @@ -0,0 +1,13 @@ +// steal from https://github.com/sindresorhus/pretty-bytes/blob/master/index.js + +const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + +export default function prettyBytes(n: number) { + if (n < 1000) { + return n + ' B'; + } + const exponent = Math.min(Math.floor(Math.log10(n) / 3), UNITS.length - 1); + n = Number((n / Math.pow(1000, exponent)).toPrecision(3)); + const unit = UNITS[exponent]; + return n + ' ' + unit; +} diff --git a/src/misc/sentry.js b/src/misc/sentry.ts index efedcb3..efedcb3 100644 --- a/src/misc/sentry.js +++ b/src/misc/sentry.ts diff --git a/src/misc/shallowEqual.js b/src/misc/shallowEqual.ts index 241b725..241b725 100644 --- a/src/misc/shallowEqual.js +++ b/src/misc/shallowEqual.ts diff --git a/src/misc/storage.js b/src/misc/storage.ts index 7424ae1..7424ae1 100644 --- a/src/misc/storage.js +++ b/src/misc/storage.ts diff --git a/src/misc/utils.ts b/src/misc/utils.ts index d07b5f5..7c2a577 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -19,7 +19,7 @@ export function debounce<T extends any[]>( fn: (...args: T) => unknown, timeout: number ) { - let timeoutId: number; + let timeoutId: ReturnType<typeof setTimeout>; return (...args: T) => { if (timeoutId) clearTimeout(timeoutId); timeoutId = setTimeout(() => { diff --git a/src/store/app.js b/src/store/app.ts index 084ee05..eda8769 100644 --- a/src/store/app.js +++ b/src/store/app.ts @@ -1,26 +1,31 @@ +import { DispatchFn, GetStateFn, State, StateApp } from 'src/store/types'; + import { loadState, saveState } from '../misc/storage'; import { debounce, trimTrailingSlash } from '../misc/utils'; import { fetchConfigs } from './configs'; import { closeModal } from './modals'; -export const getClashAPIConfig = (s) => { +export const getClashAPIConfig = (s: State) => { const idx = s.app.selectedClashAPIConfigIndex; return s.app.clashAPIConfigs[idx]; }; -export const getSelectedClashAPIConfigIndex = (s) => +export const getSelectedClashAPIConfigIndex = (s: State) => s.app.selectedClashAPIConfigIndex; -export const getClashAPIConfigs = (s) => s.app.clashAPIConfigs; -export const getTheme = (s) => s.app.theme; -export const getSelectedChartStyleIndex = (s) => s.app.selectedChartStyleIndex; -export const getLatencyTestUrl = (s) => s.app.latencyTestUrl; -export const getCollapsibleIsOpen = (s) => s.app.collapsibleIsOpen; -export const getProxySortBy = (s) => s.app.proxySortBy; -export const getHideUnavailableProxies = (s) => s.app.hideUnavailableProxies; -export const getAutoCloseOldConns = (s) => s.app.autoCloseOldConns; +export const getClashAPIConfigs = (s: State) => s.app.clashAPIConfigs; +export const getTheme = (s: State) => s.app.theme; +export const getSelectedChartStyleIndex = (s: State) => + s.app.selectedChartStyleIndex; +export const getLatencyTestUrl = (s: State) => s.app.latencyTestUrl; +export const getCollapsibleIsOpen = (s: State) => s.app.collapsibleIsOpen; +export const getProxySortBy = (s: State) => s.app.proxySortBy; +export const getHideUnavailableProxies = (s: State) => + s.app.hideUnavailableProxies; +export const getAutoCloseOldConns = (s: State) => s.app.autoCloseOldConns; const saveStateDebounced = debounce(saveState, 600); -function findClashAPIConfigIndex(getState, { baseURL, secret }) { +// @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value. +function findClashAPIConfigIndex(getState: GetStateFn, { baseURL, secret }) { const arr = getClashAPIConfigs(getState()); for (let i = 0; i < arr.length; i++) { const x = arr[i]; @@ -29,7 +34,7 @@ function findClashAPIConfigIndex(getState, { baseURL, secret }) { } export function addClashAPIConfig({ baseURL, secret }) { - return async (dispatch, getState) => { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const idx = findClashAPIConfigIndex(getState, { baseURL, secret }); // already exists if (idx) return; @@ -44,7 +49,7 @@ export function addClashAPIConfig({ baseURL, secret }) { } export function removeClashAPIConfig({ baseURL, secret }) { - return async (dispatch, getState) => { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const idx = findClashAPIConfigIndex(getState, { baseURL, secret }); dispatch('removeClashAPIConfig', (s) => { s.app.clashAPIConfigs = [ @@ -58,7 +63,7 @@ export function removeClashAPIConfig({ baseURL, secret }) { } export function selectClashAPIConfig({ baseURL, secret }) { - return async (dispatch, getState) => { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const idx = findClashAPIConfigIndex(getState, { baseURL, secret }); const curr = getSelectedClashAPIConfigIndex(getState()); if (curr !== idx) { @@ -81,7 +86,7 @@ export function selectClashAPIConfig({ baseURL, secret }) { // unused export function updateClashAPIConfig({ baseURL, secret }) { - return async (dispatch, getState) => { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const clashAPIConfig = { baseURL, secret }; dispatch('appUpdateClashAPIConfig', (s) => { s.app.clashAPIConfigs[0] = clashAPIConfig; @@ -105,7 +110,7 @@ function setTheme(theme = 'dark') { } export function switchTheme() { - return (dispatch, getState) => { + return (dispatch: DispatchFn, getState: GetStateFn) => { const currentTheme = getTheme(getState()); const theme = currentTheme === 'light' ? 'dark' : 'light'; // side effect @@ -118,8 +123,8 @@ export function switchTheme() { }; } -export function selectChartStyleIndex(selectedChartStyleIndex) { - return (dispatch, getState) => { +export function selectChartStyleIndex(selectedChartStyleIndex: number) { + return (dispatch: DispatchFn, getState: GetStateFn) => { dispatch('appSelectChartStyleIndex', (s) => { s.app.selectedChartStyleIndex = selectedChartStyleIndex; }); @@ -128,8 +133,8 @@ export function selectChartStyleIndex(selectedChartStyleIndex) { }; } -export function updateAppConfig(name, value) { - return (dispatch, getState) => { +export function updateAppConfig(name: string, value: unknown) { + return (dispatch: DispatchFn, getState: GetStateFn) => { dispatch('appUpdateAppConfig', (s) => { s.app[name] = value; }); @@ -138,9 +143,13 @@ export function updateAppConfig(name, value) { }; } -export function updateCollapsibleIsOpen(prefix, name, v) { - return (dispatch, getState) => { - dispatch('updateCollapsibleIsOpen', (s) => { +export function updateCollapsibleIsOpen( + prefix: string, + name: string, + v: boolean +) { + return (dispatch: DispatchFn, getState: GetStateFn) => { + dispatch('updateCollapsibleIsOpen', (s: State) => { s.app.collapsibleIsOpen[`${prefix}:${name}`] = v; }); // side effect @@ -154,7 +163,7 @@ const defaultClashAPIConfig = { addedAt: 0, }; // type Theme = 'light' | 'dark'; -const defaultState = { +const defaultState: StateApp = { selectedClashAPIConfigIndex: 0, clashAPIConfigs: [defaultClashAPIConfig], @@ -172,7 +181,7 @@ const defaultState = { function parseConfigQueryString() { const { search } = window.location; - const collector = {}; + const collector: Record<string, string> = {}; if (typeof search !== 'string' || search === '') return collector; const qs = search.replace(/^\?/, '').split('&'); for (let i = 0; i < qs.length; i++) { diff --git a/src/store/configs.js b/src/store/configs.ts index bcd4ac8..d18838e 100644 --- a/src/store/configs.js +++ b/src/store/configs.ts @@ -1,13 +1,23 @@ +import { + ClashGeneralConfig, + DispatchFn, + GetStateFn, + State, + StateConfigs, +} from 'src/store/types'; +import { ClashAPIConfig } from 'src/types'; + import * as configsAPI from '../api/configs'; import * as trafficAPI from '../api/traffic'; import { openModal } from './modals'; -export const getConfigs = (s) => s.configs.configs; -export const getLogLevel = (s) => s.configs.configs['log-level']; +export const getConfigs = (s: State) => s.configs.configs; +export const getHaveFetched = (s: State) => s.configs.haveFetchedConfig; +export const getLogLevel = (s: State) => s.configs.configs['log-level']; -export function fetchConfigs(apiConfig) { - return async (dispatch, getState) => { - let res; +export function fetchConfigs(apiConfig: ClashAPIConfig) { + return async (dispatch: DispatchFn, getState: GetStateFn) => { + let res: Response; try { res = await configsAPI.fetchConfigs(apiConfig); } catch (err) { @@ -28,9 +38,9 @@ export function fetchConfigs(apiConfig) { s.configs.configs = payload; }); - const configsCurr = getConfigs(getState()); + const haveFetchedConfig = getHaveFetched(getState()); - if (configsCurr.haveFetchedConfig) { + if (haveFetchedConfig) { // normally user will land on the "traffic chart" page first // calling this here will let the data start streaming // the traffic chart should already subscribed to the streaming @@ -42,15 +52,18 @@ export function fetchConfigs(apiConfig) { } function markHaveFetchedConfig() { - return (dispatch) => { - dispatch('store/configs#markHaveFetchedConfig', (s) => { + return (dispatch: DispatchFn) => { + dispatch('store/configs#markHaveFetchedConfig', (s: State) => { s.configs.haveFetchedConfig = true; }); }; } -export function updateConfigs(apiConfig, partialConfg) { - return async (dispatch) => { +export function updateConfigs( + apiConfig: ClashAPIConfig, + partialConfg: Partial<ClashGeneralConfig> +) { + return async (dispatch: DispatchFn) => { configsAPI .updateConfigs(apiConfig, partialConfg) .then( @@ -76,7 +89,7 @@ export function updateConfigs(apiConfig, partialConfg) { }; } -export const initialState = { +export const initialState: StateConfigs = { configs: { port: 7890, 'socks-port': 7891, diff --git a/src/store/index.js b/src/store/index.ts index 4fc8e4c..4fc8e4c 100644 --- a/src/store/index.js +++ b/src/store/index.ts diff --git a/src/store/logs.js b/src/store/logs.ts index 6da2b33..6da2b33 100644 --- a/src/store/logs.js +++ b/src/store/logs.ts diff --git a/src/store/modals.js b/src/store/modals.ts index 135515c..135515c 100644 --- a/src/store/modals.js +++ b/src/store/modals.ts diff --git a/src/store/proxies.tsx b/src/store/proxies.tsx index ccc5767..7c34d74 100644 --- a/src/store/proxies.tsx +++ b/src/store/proxies.tsx @@ -1,58 +1,23 @@ import { atom } from 'recoil'; +/* import { ProxyItem, ProxiesMapping, DelayMapping } from 'src/store/types'; */ +import { + DispatchFn, + FormattedProxyProvider, + GetStateFn, + ProxiesMapping, + ProxyItem, + ProxyProvider, + State, + StateProxies, + SwitchProxyCtxItem, +} from 'src/store/types'; import { ClashAPIConfig } from 'src/types'; import * as connAPI from '../api/connections'; import * as proxiesAPI from '../api/proxies'; import { getAutoCloseOldConns, getLatencyTestUrl } from './app'; -type PrimitiveProxyType = 'Shadowsocks' | 'Snell' | 'Socks5' | 'Http' | 'Vmess'; - -type LatencyHistory = Array<{ time: string; delay: number }>; - -export type ProxyItem = { - name: string; - type: PrimitiveProxyType; - history: LatencyHistory; - all?: string[]; - now?: string; -}; - -type ProxyProvider = { - name: string; - type: 'Proxy'; - updatedAt: string; - vehicleType: 'HTTP' | 'File' | 'Compatible'; - proxies: Array<ProxyItem>; -}; - -type FormattedProxyProvider = Omit<ProxyProvider, 'proxies'> & { - proxies: string[]; -}; - -export type ProxiesMapping = Record<string, ProxyItem>; -export type DelayMapping = Record<string, { number?: number }>; - -type SwitchProxyCtxItem = { groupName: string; itemName: string }; -type SwitchProxyCtx = { - to: SwitchProxyCtxItem; -}; - -type ProxiesState = { - proxies: ProxiesMapping; - delay: DelayMapping; - groupNames: string[]; - proxyProviders?: FormattedProxyProvider[]; - dangleProxyNames?: string[]; - - showModalClosePrevConns: boolean; - switchProxyCtx?: SwitchProxyCtx; -}; - -type GlobalState = { - proxies: ProxiesState; -}; - -export const initialState: ProxiesState = { +export const initialState: StateProxies = { proxies: {}, delay: {}, groupNames: [], @@ -78,14 +43,12 @@ export const NonProxyTypes = [ 'Unknown', ]; -export const getProxies = (s: GlobalState) => s.proxies.proxies; -export const getDelay = (s: GlobalState) => s.proxies.delay; -export const getProxyGroupNames = (s: GlobalState) => s.proxies.groupNames; -export const getProxyProviders = (s: GlobalState) => - s.proxies.proxyProviders || []; -export const getDangleProxyNames = (s: GlobalState) => - s.proxies.dangleProxyNames; -export const getShowModalClosePrevConns = (s: GlobalState) => +export const getProxies = (s: State) => s.proxies.proxies; +export const getDelay = (s: State) => s.proxies.delay; +export const getProxyGroupNames = (s: State) => s.proxies.groupNames; +export const getProxyProviders = (s: State) => s.proxies.proxyProviders || []; +export const getDangleProxyNames = (s: State) => s.proxies.dangleProxyNames; +export const getShowModalClosePrevConns = (s: State) => s.proxies.showModalClosePrevConns; export function fetchProxies(apiConfig: ClashAPIConfig) { @@ -120,7 +83,7 @@ export function fetchProxies(apiConfig: ClashAPIConfig) { if (!providerProxies[v]) dangleProxyNames.push(v); } - dispatch('store/proxies#fetchProxies', (s: GlobalState) => { + dispatch('store/proxies#fetchProxies', (s: State) => { s.proxies.proxies = proxies; s.proxies.groupNames = groupNames; s.proxies.delay = delayNext; @@ -131,7 +94,7 @@ export function fetchProxies(apiConfig: ClashAPIConfig) { } export function updateProviderByName(apiConfig: ClashAPIConfig, name: string) { - return async (dispatch) => { + return async (dispatch: DispatchFn) => { try { await proxiesAPI.updateProviderByName(apiConfig, name); } catch (x) { @@ -143,7 +106,10 @@ export function updateProviderByName(apiConfig: ClashAPIConfig, name: string) { }; } -async function healthcheckProviderByNameInternal(apiConfig, name) { +async function healthcheckProviderByNameInternal( + apiConfig: ClashAPIConfig, + name: string +) { try { await proxiesAPI.healthcheckProviderByName(apiConfig, name); } catch (x) { @@ -151,8 +117,11 @@ async function healthcheckProviderByNameInternal(apiConfig, name) { } } -export function healthcheckProviderByName(apiConfig, name) { - return async (dispatch) => { +export function healthcheckProviderByName( + apiConfig: ClashAPIConfig, + name: string +) { + return async (dispatch: DispatchFn) => { await healthcheckProviderByNameInternal(apiConfig, name); // should be optimized // but ¯\_(ツ)_/¯ @@ -206,8 +175,8 @@ function resolveChain( } async function switchProxyImpl( - dispatch: any, - getState: () => GlobalState, + dispatch: DispatchFn, + getState: GetStateFn, apiConfig: ClashAPIConfig, groupName: string, itemName: string @@ -243,8 +212,8 @@ async function switchProxyImpl( } function closeModalClosePrevConns() { - return (dispatch) => { - dispatch('closeModalClosePrevConns', (s: GlobalState) => { + return (dispatch: DispatchFn) => { + dispatch('closeModalClosePrevConns', (s: State) => { s.proxies.showModalClosePrevConns = false; }); }; @@ -263,7 +232,7 @@ function closePrevConns( } function closePrevConnsAndTheModal(apiConfig: ClashAPIConfig) { - return async (dispatch, getState) => { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const s = getState(); const switchTo = s.proxies.switchProxyCtx?.to; if (!switchTo) { @@ -276,15 +245,19 @@ function closePrevConnsAndTheModal(apiConfig: ClashAPIConfig) { const proxies = s.proxies.proxies; closePrevConns(apiConfig, proxies, switchTo); - dispatch('closePrevConnsAndTheModal', (s: GlobalState) => { + dispatch('closePrevConnsAndTheModal', (s: State) => { s.proxies.showModalClosePrevConns = false; s.proxies.switchProxyCtx = undefined; }); }; } -export function switchProxy(apiConfig, groupName, itemName) { - return async (dispatch, getState) => { +export function switchProxy( + apiConfig: ClashAPIConfig, + groupName: string, + itemName: string +) { + return async (dispatch: DispatchFn, getState: GetStateFn) => { // switch proxy asynchronously switchProxyImpl(dispatch, getState, apiConfig, groupName, itemName).catch( noop @@ -300,8 +273,8 @@ export function switchProxy(apiConfig, groupName, itemName) { }; } -function requestDelayForProxyOnce(apiConfig, name) { - return async (dispatch, getState) => { +function requestDelayForProxyOnce(apiConfig: ClashAPIConfig, name: string) { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const latencyTestUrl = getLatencyTestUrl(getState()); const res = await proxiesAPI.requestDelayForProxy( apiConfig, @@ -329,14 +302,17 @@ function requestDelayForProxyOnce(apiConfig, name) { }; } -export function requestDelayForProxy(apiConfig, name) { - return async (dispatch) => { +export function requestDelayForProxy(apiConfig: ClashAPIConfig, name: string) { + return async (dispatch: DispatchFn) => { await dispatch(requestDelayForProxyOnce(apiConfig, name)); }; } -export function requestDelayForProxies(apiConfig, names) { - return async (dispatch, getState) => { +export function requestDelayForProxies( + apiConfig: ClashAPIConfig, + names: string[] +) { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const proxyNames = getDangleProxyNames(getState()); const works = names @@ -348,8 +324,8 @@ export function requestDelayForProxies(apiConfig, names) { }; } -export function requestDelayAll(apiConfig) { - return async (dispatch, getState) => { +export function requestDelayAll(apiConfig: ClashAPIConfig) { + return async (dispatch: DispatchFn, getState: GetStateFn) => { const proxyNames = getDangleProxyNames(getState()); await Promise.all( proxyNames.map((p) => dispatch(requestDelayForProxy(apiConfig, p))) @@ -363,9 +339,9 @@ export function requestDelayAll(apiConfig) { }; } -function retrieveGroupNamesFrom(proxies) { +function retrieveGroupNamesFrom(proxies: Record<string, ProxyItem>) { let groupNames = []; - let globalAll; + let globalAll: string[]; const proxyNames = []; for (const prop in proxies) { const p = proxies[prop]; diff --git a/src/store/rules.js b/src/store/rules.ts index bdd835d..bdd835d 100644 --- a/src/store/rules.js +++ b/src/store/rules.ts diff --git a/src/store/types.ts b/src/store/types.ts new file mode 100644 index 0000000..5f05457 --- /dev/null +++ b/src/store/types.ts @@ -0,0 +1,91 @@ +import type { ClashAPIConfig } from 'src/types'; + +export type ClashAPIConfigWithAddedAt = ClashAPIConfig & { addedAt?: number }; +export type StateApp = { + selectedClashAPIConfigIndex: number; + clashAPIConfigs: ClashAPIConfigWithAddedAt[]; + + latencyTestUrl: string; + selectedChartStyleIndex: number; + theme: string; + + collapsibleIsOpen: Record<string, boolean>; + proxySortBy: string; + hideUnavailableProxies: boolean; + autoCloseOldConns: boolean; +}; + +export type ClashGeneralConfig = { + port: number; + 'socks-port': number; + 'redir-port': number; + 'allow-lan': boolean; + mode: string; + 'log-level': string; +}; + +///// store.proxies + +type LatencyHistory = Array<{ time: string; delay: number }>; +type PrimitiveProxyType = 'Shadowsocks' | 'Snell' | 'Socks5' | 'Http' | 'Vmess'; +export type ProxyItem = { + name: string; + type: PrimitiveProxyType; + history: LatencyHistory; + all?: string[]; + now?: string; +}; +export type ProxiesMapping = Record<string, ProxyItem>; +export type DelayMapping = Record<string, { number?: number }>; + +export type ProxyProvider = { + name: string; + type: 'Proxy'; + updatedAt: string; + vehicleType: 'HTTP' | 'File' | 'Compatible'; + proxies: Array<ProxyItem>; +}; + +export type FormattedProxyProvider = Omit<ProxyProvider, 'proxies'> & { + proxies: string[]; +}; + +export type SwitchProxyCtxItem = { groupName: string; itemName: string }; +type SwitchProxyCtx = { + to: SwitchProxyCtxItem; +}; +export type StateProxies = { + proxies: ProxiesMapping; + delay: DelayMapping; + groupNames: string[]; + proxyProviders?: FormattedProxyProvider[]; + dangleProxyNames?: string[]; + + showModalClosePrevConns: boolean; + switchProxyCtx?: SwitchProxyCtx; +}; + +///// store.configs + +export type StateConfigs = { + configs: ClashGeneralConfig; + haveFetchedConfig: boolean; +}; + +////// + +export type State = { + app: StateApp; + configs: StateConfigs; + proxies: StateProxies; +}; +export type GetStateFn = () => State; +export interface DispatchFn { + (msg: string, change: (s: State) => void): void; + ( + action: (dispatch: DispatchFn, getState: GetStateFn) => Promise<void> + ): ReturnType<typeof action>; + (action: (dispatch: DispatchFn, getState: GetStateFn) => void): ReturnType< + typeof action + >; +} |
