Chore: use eslint

This commit is contained in:
Dreamacro 2020-02-18 19:21:57 +08:00
parent 11db44dd1c
commit 9cfd15b40a
28 changed files with 3003 additions and 1366 deletions

29
.eslintrc.yml Normal file
View File

@ -0,0 +1,29 @@
env:
browser: true
es6: true
extends:
- 'plugin:react/recommended'
- 'plugin:@typescript-eslint/recommended'
- standard
globals:
Atomics: readonly
SharedArrayBuffer: readonly
parser: '@typescript-eslint/parser'
parserOptions:
ecmaFeatures:
jsx: true
ecmaVersion: 2018
sourceType: module
project: './tsconfig.json'
plugins:
- react
- '@typescript-eslint'
settings:
react:
version: 'detect'
rules:
'@typescript-eslint/indent': ['error', 4, { 'SwitchCase': 0 }]
'indent': 'off'
'@typescript-eslint/explicit-function-return-type': 'off'
'@typescript-eslint/member-delimiter-style': ['warn', { multiline: { delimiter: 'none' }, singleline: { delimiter: 'comma' } }]
'@typescript-eslint/no-explicit-any': 'off'

View File

@ -22,7 +22,7 @@ module.exports = {
{ {
test: /\.tsx?$/, test: /\.tsx?$/,
enforce: 'pre', enforce: 'pre',
use: ['tslint-loader'] use: ['eslint-loader']
}, },
{ {
test: /\.js$/, test: /\.js$/,

4044
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
"build": "npm run clean-dist && NODE_ENV=production webpack --config=configs/webpack/prod.js", "build": "npm run clean-dist && NODE_ENV=production webpack --config=configs/webpack/prod.js",
"clean-dist": "rm -rf dist", "clean-dist": "rm -rf dist",
"lint": "npm run lint:ts && npm run lint:sass", "lint": "npm run lint:ts && npm run lint:sass",
"lint:ts": "tslint './src/**/*.ts*' --format stylish", "lint:ts": "eslint --ext=jsx,ts,tsx --fix src",
"lint:sass": "stylelint './src/**/*.scss'", "lint:sass": "stylelint './src/**/*.scss'",
"start": "npm run start-dev", "start": "npm run start-dev",
"start-dev": "webpack-dev-server --config=configs/webpack/dev.js", "start-dev": "webpack-dev-server --config=configs/webpack/dev.js",
@ -28,55 +28,62 @@
"contributors:generate": "all-contributors generate" "contributors:generate": "all-contributors generate"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.7.7", "@babel/cli": "^7.8.4",
"@babel/core": "^7.7.7", "@babel/core": "^7.8.4",
"@babel/preset-env": "^7.7.7", "@babel/preset-env": "^7.8.4",
"@babel/preset-react": "^7.7.4", "@babel/preset-react": "^7.8.3",
"@hot-loader/react-dom": "^16.11.0", "@hot-loader/react-dom": "^16.11.0",
"@types/classnames": "^2.2.8", "@types/classnames": "^2.2.8",
"@types/lodash-es": "^4.17.3", "@types/lodash-es": "^4.17.3",
"@types/node": "^13.1.1", "@types/node": "^13.7.1",
"@types/react": "^16.9.17", "@types/react": "^16.9.20",
"@types/react-dom": "^16.9.4", "@types/react-dom": "^16.9.5",
"@types/react-router-dom": "^5.1.3", "@types/react-router-dom": "^5.1.3",
"@types/react-virtualized-auto-sizer": "^1.0.0", "@types/react-virtualized-auto-sizer": "^1.0.0",
"@types/react-window": "^1.8.1", "@types/react-window": "^1.8.1",
"autoprefixer": "^9.7.3", "@typescript-eslint/eslint-plugin": "^2.20.0",
"@typescript-eslint/parser": "^2.20.0",
"autoprefixer": "^9.7.4",
"awesome-typescript-loader": "^5.2.1", "awesome-typescript-loader": "^5.2.1",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"babel-preset-minify": "^0.5.1", "babel-preset-minify": "^0.5.1",
"css-loader": "^3.4.0", "css-loader": "^3.4.2",
"eslint": "^6.8.0",
"eslint-config-standard": "^14.1.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-standard": "^4.0.1",
"file-loader": "^5.0.2", "file-loader": "^5.0.2",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^6.0.0", "image-webpack-loader": "^6.0.0",
"mini-css-extract-plugin": "^0.9.0", "mini-css-extract-plugin": "^0.9.0",
"offline-plugin": "^5.0.7", "offline-plugin": "^5.0.7",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"react-hot-loader": "^4.12.18", "react-hot-loader": "^4.12.19",
"sass": "^1.24.0", "sass": "^1.25.0",
"sass-loader": "^8.0.0", "sass-loader": "^8.0.2",
"style-loader": "^1.1.2", "style-loader": "^1.1.3",
"stylelint": "^12.0.1", "stylelint": "^13.2.0",
"stylelint-config-standard": "^19.0.0", "stylelint-config-standard": "^20.0.0",
"stylelint-webpack-plugin": "^1.1.2", "stylelint-webpack-plugin": "^1.2.3",
"terser-webpack-plugin": "^2.3.1", "terser-webpack-plugin": "^2.3.5",
"tslint": "^5.20.1", "typescript": "^3.7.5",
"tslint-config-standard": "^9.0.0", "webpack": "^4.41.6",
"tslint-loader": "^3.6.0", "webpack-cli": "^3.3.11",
"typescript": "^3.7.4",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-middleware": "^3.7.2", "webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.10.1", "webpack-dev-server": "^3.10.3",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpack-pwa-manifest": "^4.1.1" "webpack-pwa-manifest": "^4.2.0"
}, },
"dependencies": { "dependencies": {
"axios": "^0.19.0", "axios": "^0.19.2",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"dayjs": "^1.8.18", "dayjs": "^1.8.20",
"eventemitter3": "^4.0.0", "eventemitter3": "^4.0.0",
"immer": "^5.1.0", "immer": "^5.3.6",
"lodash-es": "^4.17.15", "lodash-es": "^4.17.15",
"react": "^16.12.0", "react": "^16.12.0",
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
@ -84,7 +91,7 @@
"react-table": "^7.0.0-beta.12", "react-table": "^7.0.0-beta.12",
"react-virtualized-auto-sizer": "^1.0.2", "react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5", "react-window": "^1.8.5",
"swr": "^0.1.16", "swr": "^0.1.17",
"unstated-next": "^1.1.0", "unstated-next": "^1.1.0",
"use-immer": "^0.3.5" "use-immer": "^0.3.5"
} }

View File

@ -3,20 +3,20 @@ import { BaseComponentProps } from '@models/BaseProps'
import classnames from 'classnames' import classnames from 'classnames'
import './style.scss' import './style.scss'
export interface ButtonSelectOptions { export interface ButtonSelectOptions<T = string> {
label: string, label: string
value: any value: T
} }
export interface ButtonSelectProps extends BaseComponentProps { export interface ButtonSelectProps<T = string> extends BaseComponentProps {
// options // options
options: ButtonSelectOptions[] options: ButtonSelectOptions<T>[]
// active value // active value
value: any value: T
// select callback // select callback
onSelect?: (value: any) => void onSelect?: (value: T) => void
} }
export function ButtonSelect (props: ButtonSelectProps) { export function ButtonSelect (props: ButtonSelectProps) {

View File

@ -3,7 +3,7 @@ import { BaseComponentProps } from '@models/BaseProps'
import classnames from 'classnames' import classnames from 'classnames'
import './style.scss' import './style.scss'
interface CardProps extends BaseComponentProps {} type CardProps = BaseComponentProps
export function Card (props: CardProps) { export function Card (props: CardProps) {
const { className, style, children } = props const { className, style, children } = props

View File

@ -4,7 +4,7 @@ import { BaseComponentProps } from '@models/BaseProps'
import './style.scss' import './style.scss'
interface SpinnerProps extends BaseComponentProps {} type SpinnerProps = BaseComponentProps
export function Spinner (props: SpinnerProps) { export function Spinner (props: SpinnerProps) {
const classname = classnames('spinner', props.className) const classname = classnames('spinner', props.className)

View File

@ -63,30 +63,6 @@ export function Message (props: MessageProps) {
) )
} }
export const info = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'info', content, duration, onClose })
export const success = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'success', content, duration, onClose })
export const warning = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'warning', content, duration, onClose })
export const error = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'error', content, duration, onClose })
export function showMessage (args: ArgsProps) { export function showMessage (args: ArgsProps) {
// create container element // create container element
const container = document.createElement('div') const container = document.createElement('div')
@ -113,3 +89,27 @@ export function showMessage (args: ArgsProps) {
render(<Message {...props} />, container) render(<Message {...props} />, container)
} }
export const info = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'info', content, duration, onClose })
export const success = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'success', content, duration, onClose })
export const warning = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'warning', content, duration, onClose })
export const error = (
content: string,
duration?: number,
onClose?: typeof noop
) => showMessage({ type: 'error', content, duration, onClose })

View File

@ -37,7 +37,7 @@ export function Modal (props: ModalProps) {
show = true, show = true,
title = 'Modal', title = 'Modal',
size = 'small', size = 'small',
footer= true, footer = true,
onOk = noop, onOk = noop,
onClose = noop, onClose = noop,
bodyClassName, bodyClassName,

View File

@ -2,6 +2,7 @@ import React, { useRef, useLayoutEffect, useState, useMemo } from 'react'
import classnames from 'classnames' import classnames from 'classnames'
import { Icon } from '@components' import { Icon } from '@components'
import { BaseComponentProps } from '@models' import { BaseComponentProps } from '@models'
import { noop } from '@lib/helper'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
import './style.scss' import './style.scss'
@ -24,16 +25,6 @@ export function Select (props: SelectProps) {
const attachmentRef = useRef<HTMLDivElement>() const attachmentRef = useRef<HTMLDivElement>()
const targetRef = useRef<HTMLDivElement>() const targetRef = useRef<HTMLDivElement>()
useLayoutEffect(() => {
document.addEventListener('click', handleGlobalClick, true)
return () => {
document.addEventListener('click', handleGlobalClick, true)
if (portalRef.current) {
document.body.removeChild(portalRef.current)
}
}
}, [])
const [showDropDownList, setShowDropDownList] = useState(false) const [showDropDownList, setShowDropDownList] = useState(false)
const [hasCreateDropList, setHasCreateDropList] = useState(false) const [hasCreateDropList, setHasCreateDropList] = useState(false)
const dropdownListStyles = useMemo(() => { const dropdownListStyles = useMemo(() => {
@ -47,15 +38,25 @@ export function Select (props: SelectProps) {
return {} return {}
}, []) }, [])
function handleGlobalClick (e) { function handleGlobalClick (e: MouseEvent) {
const el = attachmentRef.current const el = attachmentRef.current
if (el && !el.contains(e.target)) { if (el?.contains(e.target as Node)) {
setShowDropDownList(false) setShowDropDownList(false)
} }
} }
function handleShowDropList (e) { useLayoutEffect(() => {
document.addEventListener('click', handleGlobalClick, true)
return () => {
document.addEventListener('click', handleGlobalClick, true)
if (portalRef.current) {
document.body.removeChild(portalRef.current)
}
}
}, [])
function handleShowDropList () {
if (!hasCreateDropList) { if (!hasCreateDropList) {
if (!portalRef.current) { if (!portalRef.current) {
// create container element // create container element
@ -140,7 +141,7 @@ interface OptionProps extends BaseComponentProps {
} }
export function Option (props: OptionProps) { export function Option (props: OptionProps) {
const { className: cn, style, key, disabled = false, children, onClick = () => {} } = props const { className: cn, style, key, disabled = false, children, onClick = noop } = props
const className = classnames('option', { disabled }, cn) const className = classnames('option', { disabled }, cn)
return ( return (

View File

@ -21,7 +21,7 @@ function App () {
}, []) }, [])
const routes = [ const routes = [
// { path: '/', name: 'Overview', component: Overview, exact: true }, // { path: '/', name: 'Overview', component: Overview, exact: true },
{ path: '/proxies', name: 'Proxies', component: Proxies }, { path: '/proxies', name: 'Proxies', component: Proxies },
{ path: '/logs', name: 'Logs', component: Logs }, { path: '/logs', name: 'Logs', component: Logs },
{ path: '/rules', name: 'Rules', component: Rules, noMobile: true }, { path: '/rules', name: 'Rules', component: Rules, noMobile: true },

View File

@ -109,7 +109,7 @@ export default function Connections () {
}) })
.map(c => ({ .map(c => ({
id: c.id, id: c.id,
host: `${ c.metadata.host || c.metadata.destinationIP }:${ c.metadata.destinationPort }`, host: `${c.metadata.host || c.metadata.destinationIP}:${c.metadata.destinationPort}`,
chains: c.chains.slice().reverse().join(' --> '), chains: c.chains.slice().reverse().join(' --> '),
rule: c.rule, rule: c.rule,
time: fromNow(new Date(c.start), lang), time: fromNow(new Date(c.start), lang),
@ -141,7 +141,7 @@ export default function Connections () {
), [lang, t]) ), [lang, t])
useEffect(() => { useEffect(() => {
let streamReader: StreamReader<API.Snapshot> = null const streamReader: StreamReader<API.Snapshot> = null
function handleConnection (snapshots: API.Snapshot[]) { function handleConnection (snapshots: API.Snapshot[]) {
for (const snapshot of snapshots) { for (const snapshot of snapshots) {
@ -154,10 +154,10 @@ export default function Connections () {
} }
} }
void async function () { ;(async function () {
const streamReader = await API.getConnectionStreamReader() const streamReader = await API.getConnectionStreamReader()
streamReader.subscribe('data', handleConnection) streamReader.subscribe('data', handleConnection)
}() }())
return () => { return () => {
if (streamReader) { if (streamReader) {
@ -179,18 +179,18 @@ export default function Connections () {
useResizeColumns useResizeColumns
) )
const headerGroup = useMemo(() => headerGroups[0], [headerGroups]) const headerGroup = useMemo(() => headerGroups[0], [headerGroups])
const renderItem = useMemo(() => rows.map((row, index) => { const renderItem = useMemo(() => rows.map((row, i) => {
prepareRow(row) prepareRow(row)
return ( return (
<div {...row.getRowProps()} className="connections-item"> <div {...row.getRowProps()} className="connections-item" key={i}>
{ {
row.cells.map((cell) => { row.cells.map((cell, j) => {
const classname = classnames( const classname = classnames(
'connections-block', 'connections-block',
{ center: shouldCenter.has(cell.column.id), completed: !!(row.original as any).completed } { center: shouldCenter.has(cell.column.id), completed: !!(row.original as any).completed }
) )
return ( return (
<div {...cell.getCellProps()} className={classname}> <div {...cell.getCellProps()} className={classname} key={j}>
{ cell.render('Cell') } { cell.render('Cell') }
</div> </div>
) )
@ -204,7 +204,7 @@ export default function Connections () {
<div className="page"> <div className="page">
<Header title={t('title')}> <Header title={t('title')}>
<span className="connections-filter total"> <span className="connections-filter total">
{ `(${t('total.text')}: ${t('total.upload')} ${ formatTraffic(traffic.uploadTotal) } ${t('total.download')} ${ formatTraffic(traffic.downloadTotal) })` } { `(${t('total.text')}: ${t('total.upload')} ${formatTraffic(traffic.uploadTotal)} ${t('total.download')} ${formatTraffic(traffic.downloadTotal)})` }
</span> </span>
<Checkbox className="connections-filter" checked={save} onChange={toggleSave}>{ t('keepClosed') }</Checkbox> <Checkbox className="connections-filter" checked={save} onChange={toggleSave}>{ t('keepClosed') }</Checkbox>
<Icon className="connections-filter dangerous" onClick={show} type="close-all" size={20} /> <Icon className="connections-filter dangerous" onClick={show} type="close-all" size={20} />
@ -217,7 +217,7 @@ export default function Connections () {
const id = column.id const id = column.id
const handleClick = couldSort.has(id) ? () => handleSort(id) : noop const handleClick = couldSort.has(id) ? () => handleSort(id) : noop
return ( return (
<div {...column.getHeaderProps()} className="connections-th" onClick={handleClick}> <div {...column.getHeaderProps()} className="connections-th" onClick={handleClick} key={id}>
{ column.render('Header') } { column.render('Header') }
{ {
sort.column === id && (sort.asc ? ' ↑' : ' ↓') sort.column === id && (sort.asc ? ' ↑' : ' ↓')

View File

@ -20,19 +20,19 @@ export default function Logs () {
}, [logsRef.current]) }, [logsRef.current])
useEffect(() => { useEffect(() => {
let streamReader: StreamReader<Log> = null const streamReader: StreamReader<Log> = null
function handleLog (newLogs: Log[]) { function handleLog (newLogs: Log[]) {
logsRef.current = logsRef.current.slice().concat(newLogs.map(d => ({ ...d, time: new Date() }))) logsRef.current = logsRef.current.slice().concat(newLogs.map(d => ({ ...d, time: new Date() })))
setLogs(logsRef.current) setLogs(logsRef.current)
} }
void async function () { ;(async function () {
const streamReader = await getLogsStreamReader() const streamReader = await getLogsStreamReader()
logsRef.current = streamReader.buffer() logsRef.current = streamReader.buffer()
setLogs(logsRef.current) setLogs(logsRef.current)
streamReader.subscribe('data', handleLog) streamReader.subscribe('data', handleLog)
}() }())
return () => streamReader && streamReader.unsubscribe('data', handleLog) return () => streamReader && streamReader.unsubscribe('data', handleLog)
}, []) }, [])

View File

@ -1,5 +1,5 @@
import * as React from 'react' import * as React from 'react'
const logo = require('@assets/LOGO-fixing.svg') import logo from '@assets/logo-fixing.svg'
export default function Overview () { export default function Overview () {
return ( return (

View File

@ -15,7 +15,7 @@ export default function Rules () {
fetch() fetch()
}, []) }, [])
function renderRuleItem ({ index, style }) { function renderRuleItem ({ index, style }: { index: number, style: React.CSSProperties }) {
const rule = rules[index] const rule = rules[index]
return ( return (
<li className="rule-item" style={style}> <li className="rule-item" style={style}>

View File

@ -56,7 +56,7 @@ export default function Settings () {
} }
async function handleHttpPortSave () { async function handleHttpPortSave () {
const [, err] = await to(updateConfig({ 'port': info.httpProxyPort })) const [, err] = await to(updateConfig({ port: info.httpProxyPort }))
if (!err) { if (!err) {
await fetch() await fetch()
set('httpProxyPort', data.general.port) set('httpProxyPort', data.general.port)

5
src/global.d.ts vendored
View File

@ -2,3 +2,8 @@ declare module '*.png' {
const content: string const content: string
export default content export default content
} }
declare module '*.svg' {
const content: string
export default content
}

View File

@ -1,3 +1,5 @@
/* eslint-disable camelcase */
/* eslint-disable @typescript-eslint/camelcase */
import { useState, useCallback } from 'react' import { useState, useCallback } from 'react'
import get from 'lodash/get' import get from 'lodash/get'
import { getLocalStorageItem, setLocalStorageItem } from '@lib/helper' import { getLocalStorageItem, setLocalStorageItem } from '@lib/helper'

View File

@ -10,6 +10,7 @@ export function removeLocalStorageItem (key: string) {
return window.localStorage.removeItem(key) return window.localStorage.removeItem(key)
} }
// eslint-disable-next-line @typescript-eslint/no-empty-function
export function noop () {} export function noop () {}
/** /**

View File

@ -37,7 +37,9 @@ export function useObject<T extends object> (initialValue: T) {
export function useInterval (callback: () => void, delay: number) { export function useInterval (callback: () => void, delay: number) {
const savedCallback = useRef(noop) const savedCallback = useRef(noop)
useEffect(() => savedCallback.current = callback, [callback]) useEffect(() => {
savedCallback.current = callback
}, [callback])
useEffect( useEffect(
() => { () => {

View File

@ -52,6 +52,8 @@ declare global {
} }
type JsBridgeCallback = (jsbridge: JsBridgeAPI) => void
/** /**
* Check if perched in ClashX Runtime * Check if perched in ClashX Runtime
*/ */
@ -68,10 +70,9 @@ export let jsBridge: JsBridge = null
* JsBridge class * JsBridge class
*/ */
export class JsBridge { export class JsBridge {
instance: JsBridgeAPI = null instance: JsBridgeAPI = null
constructor (callback = jsbridge => {}) { constructor (callback: JsBridgeCallback) {
if (window.WebViewJavascriptBridge) { if (window.WebViewJavascriptBridge) {
this.instance = window.WebViewJavascriptBridge this.instance = window.WebViewJavascriptBridge
callback(this.instance) callback(this.instance)
@ -89,7 +90,7 @@ export class JsBridge {
* @param {Function} cb callback when jsbridge initialized * @param {Function} cb callback when jsbridge initialized
* @see https://github.com/marcuswestin/WebViewJavascriptBridge * @see https://github.com/marcuswestin/WebViewJavascriptBridge
*/ */
private initBridge (callback) { private initBridge (callback: JsBridgeCallback) {
/** /**
* You need check if inClashX first * You need check if inClashX first
*/ */

View File

@ -87,6 +87,28 @@ export interface Connections {
rule: string rule: string
} }
export async function getExternalControllerConfig () {
if (isClashX()) {
const info = await jsBridge.getAPIInfo()
return {
hostname: info.host,
port: info.port,
secret: info.secret
}
}
const hostname = getLocalStorageItem('externalControllerAddr', '127.0.0.1')
const port = getLocalStorageItem('externalControllerPort', '9090')
const secret = getLocalStorageItem('secret', '')
if (!hostname || !port) {
throw new Error('can\'t get hostname or port')
}
return { hostname, port, secret }
}
export const getInstance = createAsyncSingleton(async () => { export const getInstance = createAsyncSingleton(async () => {
const { const {
hostname, hostname,
@ -129,12 +151,12 @@ export async function getProxyProviders () {
} }
}) })
// compatible old version // compatible old version
.then(resp => { .then(resp => {
if (resp.status === 404) { if (resp.status === 404) {
resp.data = { providers: {} } resp.data = { providers: {} }
} }
return resp return resp
}) })
} }
export async function updateProvider (name: string) { export async function updateProvider (name: string) {
@ -182,28 +204,6 @@ export async function changeProxySelected (name: string, select: string) {
return req.put<void>(`proxies/${name}`, { name: select }) return req.put<void>(`proxies/${name}`, { name: select })
} }
export async function getExternalControllerConfig () {
if (isClashX()) {
const info = await jsBridge.getAPIInfo()
return {
hostname: info.host,
port: info.port,
secret: info.secret
}
}
const hostname = getLocalStorageItem('externalControllerAddr', '127.0.0.1')
const port = getLocalStorageItem('externalControllerPort', '9090')
const secret = getLocalStorageItem('secret', '')
if (!hostname || !port) {
throw new Error('can\'t get hostname or port')
}
return { hostname, port, secret }
}
export const getLogsStreamReader = createAsyncSingleton(async function () { export const getLogsStreamReader = createAsyncSingleton(async function () {
const externalController = await getExternalControllerConfig() const externalController = await getExternalControllerConfig()
const { data: config } = await getConfig() const { data: config } = await getConfig()

View File

@ -5,7 +5,7 @@ import { RouteComponentProps } from 'react-router'
* expose base router component props * expose base router component props
* and mobx store to props * and mobx store to props
*/ */
export interface BaseRouterProps extends RouteComponentProps<any> {} export type BaseRouterProps = RouteComponentProps
export interface BaseComponentProps { export interface BaseComponentProps {
className?: string className?: string

View File

@ -1,5 +1,5 @@
export interface Log { export interface Log {
type: string type: string
payload: string, payload: string
time: Date time: Date
} }

View File

@ -90,7 +90,7 @@ export interface FallbackProxyGroup {
url?: string url?: string
interval?: number // second interval?: number // second
} }
export interface UrlTestProxyGroup { export interface UrlTestProxyGroup {
@ -102,5 +102,5 @@ export interface UrlTestProxyGroup {
url?: string url?: string
interval?: number // second interval?: number // second
} }

View File

@ -4,7 +4,7 @@ export interface Rule {
payload?: string payload?: string
proxy?: string // proxy or proxy group name proxy?: string // proxy or proxy group name
} }

View File

@ -45,7 +45,7 @@ function useData () {
const policyGroup = new Set(['Selector', 'URLTest', 'Fallback', 'LoadBalance']) const policyGroup = new Set(['Selector', 'URLTest', 'Fallback', 'LoadBalance'])
const unUsedProxy = new Set(['DIRECT', 'REJECT', 'GLOBAL']) const unUsedProxy = new Set(['DIRECT', 'REJECT', 'GLOBAL'])
const proxyList = rawProxies.data.proxies['GLOBAL'] as API.Group const proxyList = rawProxies.data.proxies.GLOBAL as API.Group
// fix missing name // fix missing name
proxyList.name = 'GLOBAL' proxyList.name = 'GLOBAL'
const proxies = proxyList.all const proxies = proxyList.all

View File

@ -1,9 +0,0 @@
{
"extends": "tslint-config-standard",
"rules": {
"indent": [true, "spaces", 4],
"ter-indent": [true, 4],
"no-empty": false,
"quotemark": [true, "single", "jsx-double"]
}
}