mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 22:11:56 +08:00
Chore: adjust architecture
This commit is contained in:
parent
715827c94d
commit
60b38e7236
@ -32,8 +32,9 @@ export class ButtonSelect extends React.Component<ButtonSelectProps, {}> {
|
|||||||
value={option.value}
|
value={option.value}
|
||||||
key={option.value}
|
key={option.value}
|
||||||
className={classnames('button-select-options', { actived: value === option.value })}
|
className={classnames('button-select-options', { actived: value === option.value })}
|
||||||
onClick={() => onSelect(option.value)}
|
onClick={() => onSelect(option.value)}>
|
||||||
>{option.label}</button>
|
{ option.label }
|
||||||
|
</button>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,49 +1,32 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { BaseComponentProps } from '@models/BaseProps'
|
||||||
import { Icon } from '@components'
|
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface TagsProps extends BaseComponentProps {
|
interface TagsProps extends BaseComponentProps {
|
||||||
data: Set<string>
|
data: Set<string>
|
||||||
showAdd: boolean
|
onClick: (name: string) => void
|
||||||
onDelete: (tag: string) => void
|
selected: string
|
||||||
onAdd: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Tags extends React.Component<TagsProps, {}> {
|
export class Tags extends React.Component<TagsProps, {}> {
|
||||||
static defaultProps: TagsProps = {
|
|
||||||
data: new Set(),
|
|
||||||
showAdd: true,
|
|
||||||
onDelete: () => {},
|
|
||||||
onAdd: () => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { className, data, onDelete, onAdd, showAdd } = this.props
|
const { className, data, onClick, selected } = this.props
|
||||||
|
|
||||||
const tags = [...data]
|
const tags = [...data]
|
||||||
.sort()
|
.sort()
|
||||||
.map(t => (
|
.map(t => {
|
||||||
<li>
|
const tagClass = classnames({ 'tags-selected': selected === t })
|
||||||
|
return (
|
||||||
|
<li className={tagClass} key={t} onClick={() => onClick(t)}>
|
||||||
{ t }
|
{ t }
|
||||||
<Icon
|
|
||||||
className="tags-delete"
|
|
||||||
type="plus"
|
|
||||||
size={12}
|
|
||||||
style={{ fontWeight: 'bold', color: '#fff' }}
|
|
||||||
onClick={() => onDelete(t)}/>
|
|
||||||
</li>
|
</li>
|
||||||
))
|
)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className={classnames('tags', className)}>
|
<ul className={classnames('tags', className)}>
|
||||||
{ tags }
|
{ tags }
|
||||||
{
|
|
||||||
showAdd &&
|
|
||||||
<li className="tags-add" onClick={onAdd}>
|
|
||||||
<Icon type="plus" size={12} style={{ fontWeight: 'bold', color: '#fff' }} />
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ul>
|
</ul>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,46 +16,18 @@ $delete-height: 22px;
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border: 1px solid $color-primary-darken;
|
border: 1px solid $color-primary-dark;
|
||||||
color: $color-primary-darken;
|
color: $color-primary-darken;
|
||||||
height: $height;
|
height: $height;
|
||||||
border-radius: $height / 2;
|
border-radius: $height / 2;
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
margin: 3px 4px;
|
margin: 3px 4px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
.tags-delete {
|
|
||||||
position: absolute;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
right: -$delete-height / 2;
|
|
||||||
top: -$delete-height / 2;
|
|
||||||
height: $delete-height;
|
|
||||||
width: $delete-height;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: $color-red;
|
|
||||||
transform: rotate(45deg) scale(0.7);
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .tags-delete {
|
.tags-selected {
|
||||||
opacity: 1;
|
background-color: $color-primary-dark;
|
||||||
}
|
color: #fff;
|
||||||
}
|
|
||||||
|
|
||||||
li.tags-add {
|
|
||||||
height: $add-height;
|
|
||||||
width: $add-height;
|
|
||||||
border: none;
|
|
||||||
text-align: center;
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: $color-primary-darken;
|
|
||||||
transform: translateX(-2px) scale(0.7);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
src/containers/Proxies/components/Group/index.tsx
Normal file
33
src/containers/Proxies/components/Group/index.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import { inject } from 'mobx-react'
|
||||||
|
import { BaseComponentProps } from '@models'
|
||||||
|
import { ConfigStore } from '@stores'
|
||||||
|
import { changeProxySelected, Group as IGroup } from '@lib/request'
|
||||||
|
import { storeKeys } from '@lib/createStore'
|
||||||
|
import { Tags } from '@components'
|
||||||
|
import './style.scss'
|
||||||
|
|
||||||
|
interface GroupProps extends BaseComponentProps {
|
||||||
|
config: IGroup
|
||||||
|
store?: ConfigStore
|
||||||
|
}
|
||||||
|
|
||||||
|
@inject(...storeKeys)
|
||||||
|
export class Group extends React.Component<GroupProps, {}> {
|
||||||
|
handleChangeProxySelected = async (name: string) => {
|
||||||
|
await changeProxySelected(this.props.config.name, name)
|
||||||
|
await this.props.store.fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { config } = this.props
|
||||||
|
const proxies = new Set(config.all)
|
||||||
|
return (
|
||||||
|
<div className="proxy-group">
|
||||||
|
<span className="proxy-group-name">{ config.name }</span>
|
||||||
|
<span className="proxy-group-type">{ config.type }</span>
|
||||||
|
<Tags className="proxy-group-tags" data={proxies} onClick={this.handleChangeProxySelected} selected={config.now} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
42
src/containers/Proxies/components/Group/style.scss
Normal file
42
src/containers/Proxies/components/Group/style.scss
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
@import '~@styles/variables';
|
||||||
|
|
||||||
|
.proxy-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 12px 0;
|
||||||
|
color: $color-black-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-group-name {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 20px;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-group-type {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
width: 80px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: $color-primary-dark;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxies-group-card {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxies-group-item {
|
||||||
|
border-bottom: 1px solid $color-gray;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-group-tags {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
@ -1,14 +1,14 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { Icon } from '@components'
|
// import { Icon } from '@components'
|
||||||
import { BaseComponentProps, Proxy as IProxy, TagColors } from '@models'
|
import { BaseComponentProps, TagColors } from '@models'
|
||||||
import { getProxyDelay } from '@lib/request'
|
import { getProxyDelay, Proxy as IProxy } from '@lib/request'
|
||||||
import { to, getLocalStorageItem, setLocalStorageItem, sample, noop } from '@lib/helper'
|
import { to, getLocalStorageItem, setLocalStorageItem, sample } from '@lib/helper'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface ProxyProps extends BaseComponentProps {
|
interface ProxyProps extends BaseComponentProps {
|
||||||
config: IProxy
|
config: IProxy
|
||||||
onEdit?: (e: React.MouseEvent<HTMLElement>) => void
|
// onEdit?: (e: React.MouseEvent<HTMLElement>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProxyState {
|
interface ProxyState {
|
||||||
@ -18,8 +18,6 @@ interface ProxyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
||||||
private mount = true
|
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
@ -49,18 +47,10 @@ export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
this.mount = false
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount () {
|
async componentDidMount () {
|
||||||
const { config } = this.props
|
const { config } = this.props
|
||||||
const [res, err] = await to(getProxyDelay(config.name))
|
const [res, err] = await to(getProxyDelay(config.name))
|
||||||
|
|
||||||
if (!this.mount) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return this.setState({ hasError: true })
|
return this.setState({ hasError: true })
|
||||||
}
|
}
|
||||||
@ -70,7 +60,7 @@ export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { config, className, onEdit = noop } = this.props
|
const { config, className } = this.props
|
||||||
const { delay, color, hasError } = this.state
|
const { delay, color, hasError } = this.state
|
||||||
const backgroundColor = hasError ? undefined : color
|
const backgroundColor = hasError ? undefined : color
|
||||||
|
|
||||||
@ -79,7 +69,7 @@ export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
|||||||
<span className="proxy-type" style={{ backgroundColor }}>{config.type}</span>
|
<span className="proxy-type" style={{ backgroundColor }}>{config.type}</span>
|
||||||
<p className="proxy-name">{config.name}</p>
|
<p className="proxy-name">{config.name}</p>
|
||||||
<p className="proxy-delay">{delay === -1 ? '-' : `${delay}ms`}</p>
|
<p className="proxy-delay">{delay === -1 ? '-' : `${delay}ms`}</p>
|
||||||
<Icon className="proxy-editor" type="setting" onClick={onEdit} />
|
{/* <Icon className="proxy-editor" type="setting" onClick={onEdit} /> */}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export * from './Proxy'
|
export * from './Proxy'
|
||||||
|
export * from './Group'
|
||||||
export * from './ModifyProxyDialog'
|
export * from './ModifyProxyDialog'
|
||||||
|
@ -2,79 +2,56 @@ import * as React from 'react'
|
|||||||
import { translate } from 'react-i18next'
|
import { translate } from 'react-i18next'
|
||||||
import { inject, observer } from 'mobx-react'
|
import { inject, observer } from 'mobx-react'
|
||||||
import { storeKeys } from '@lib/createStore'
|
import { storeKeys } from '@lib/createStore'
|
||||||
import { Header, Icon } from '@components'
|
import { Card, Header } from '@components'
|
||||||
import { I18nProps, BaseRouterProps, Proxy as IProxy } from '@models'
|
import { I18nProps, BaseRouterProps } from '@models'
|
||||||
|
|
||||||
import { Proxy, ModifyProxyDialog } from './components'
|
import { Proxy, Group } from './components'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface ProxiesProps extends BaseRouterProps, I18nProps {}
|
interface ProxiesProps extends BaseRouterProps, I18nProps {}
|
||||||
|
|
||||||
interface ProxiesState {
|
interface ProxiesState {
|
||||||
showModifyProxyDialog: boolean
|
|
||||||
activeConfig?: IProxy
|
|
||||||
activeConfigIndex?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@inject(...storeKeys)
|
@inject(...storeKeys)
|
||||||
@observer
|
@observer
|
||||||
class Proxies extends React.Component<ProxiesProps, ProxiesState> {
|
class Proxies extends React.Component<ProxiesProps, ProxiesState> {
|
||||||
|
|
||||||
state = {
|
|
||||||
showModifyProxyDialog: false,
|
|
||||||
activeConfig: null,
|
|
||||||
activeConfigIndex: -1
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.props.config.fetchAndParseConfig()
|
this.props.store.fetchData()
|
||||||
}
|
|
||||||
|
|
||||||
handleConfigApply = async (config: IProxy) => {
|
|
||||||
await this.props.config.modifyProxyByIndexAndSave(this.state.activeConfigIndex, config)
|
|
||||||
this.setState({ showModifyProxyDialog: false, activeConfig: null })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { t, config } = this.props
|
const { t, store } = this.props
|
||||||
const { showModifyProxyDialog, activeConfig } = this.state
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<div className="proxies-container">
|
<div className="proxies-container">
|
||||||
<Header title={t('title')} >
|
<Header title={t('groupTitle')} />
|
||||||
<Icon type="plus" size={20} style={{ fontWeight: 'bold' }} />
|
<Card className="proxies-group-card">
|
||||||
</Header>
|
<ul className="proxies-group-list">
|
||||||
{
|
{
|
||||||
config.config.proxy.length !== 0 && <ul className="proxies-list">
|
store.data.proxyGroup.map(p => (
|
||||||
{
|
<li className="proxies-group-item" key={p.name}>
|
||||||
config.config.proxy.map((p, index) => (
|
<Group config={p} />
|
||||||
<li key={p.name}>
|
|
||||||
<Proxy config={p} onEdit={() => this.setState({
|
|
||||||
showModifyProxyDialog: true,
|
|
||||||
activeConfig: p,
|
|
||||||
activeConfigIndex: index
|
|
||||||
})} />
|
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
}
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div className="proxies-container">
|
<div className="proxies-container">
|
||||||
<Header title={t('groupTitle')} />
|
<Header title={t('title')} />
|
||||||
</div>
|
<ul className="proxies-list">
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
showModifyProxyDialog && <ModifyProxyDialog
|
store.data.proxy.map(p => (
|
||||||
config={activeConfig}
|
<li key={p.name}>
|
||||||
onOk={this.handleConfigApply}
|
<Proxy config={p} />
|
||||||
onCancel={() => this.setState({ showModifyProxyDialog: false, activeConfig: null, activeConfigIndex: -1 })}
|
</li>
|
||||||
/>
|
))
|
||||||
}
|
}
|
||||||
</>
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,3 +15,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.proxies-group-list {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxies-group-card {
|
||||||
|
margin: 15px 0 20px;
|
||||||
|
}
|
||||||
|
@ -13,12 +13,12 @@ interface RulesProps extends BaseRouterProps, I18nProps {}
|
|||||||
class Rules extends React.Component<RulesProps, {}> {
|
class Rules extends React.Component<RulesProps, {}> {
|
||||||
|
|
||||||
async componentDidMount () {
|
async componentDidMount () {
|
||||||
const { config } = this.props
|
const { store } = this.props
|
||||||
await config.fetchAndParseConfig()
|
await store.fetchData()
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRuleItem = ({ index, key, style }) => {
|
renderRuleItem = ({ index, key, style }) => {
|
||||||
const { rules } = this.props.config.config
|
const { rules } = this.props.store.data
|
||||||
const rule = rules[index]
|
const rule = rules[index]
|
||||||
return (
|
return (
|
||||||
<li className="rule-item" key={key} style={style}>
|
<li className="rule-item" key={key} style={style}>
|
||||||
@ -39,7 +39,7 @@ class Rules extends React.Component<RulesProps, {}> {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { t } = this.props
|
const { t } = this.props
|
||||||
const { rules } = this.props.config.config
|
const { rules } = this.props.store.config
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<Header title={t('title')} />
|
<Header title={t('title')} />
|
||||||
|
@ -79,7 +79,7 @@ class Settings extends React.Component<I18nProps, {}> {
|
|||||||
|
|
||||||
async componentDidMount () {
|
async componentDidMount () {
|
||||||
if (isClashX()) {
|
if (isClashX()) {
|
||||||
await rootStores.config.fetchAndParseConfig()
|
await rootStores.store.fetchAndParseConfig()
|
||||||
const startAtLogin = await jsBridge.getStartAtLogin()
|
const startAtLogin = await jsBridge.getStartAtLogin()
|
||||||
const setAsSystemProxy = await jsBridge.isSystemProxySet()
|
const setAsSystemProxy = await jsBridge.isSystemProxySet()
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -88,9 +88,9 @@ class Settings extends React.Component<I18nProps, {}> {
|
|||||||
isClashX: true
|
isClashX: true
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
await rootStores.config.fetchConfig()
|
await rootStores.store.fetchConfig()
|
||||||
}
|
}
|
||||||
const general = rootStores.config.config.general
|
const general = rootStores.store.config.general
|
||||||
this.setState({
|
this.setState({
|
||||||
allowConnectFromLan: general.allowLan,
|
allowConnectFromLan: general.allowLan,
|
||||||
proxyMode: general.mode,
|
proxyMode: general.mode,
|
||||||
|
@ -8,7 +8,7 @@ const history = createHashHistory()
|
|||||||
|
|
||||||
export const rootStores = {
|
export const rootStores = {
|
||||||
router: new RouterStore(history),
|
router: new RouterStore(history),
|
||||||
config: new ConfigStore()
|
store: new ConfigStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const storeKeys = Object.keys(rootStores)
|
export const storeKeys = Object.keys(rootStores)
|
||||||
|
@ -34,3 +34,12 @@ export async function to <T, E = Error> (promise: Promise<T>): Promise<[T, E]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Partial<T> = { [P in keyof T]?: T[P] }
|
export type Partial<T> = { [P in keyof T]?: T[P] }
|
||||||
|
|
||||||
|
export function partition<T> (arr: T[], fn: (T) => boolean): [T[], T[]] {
|
||||||
|
const left: T[] = []
|
||||||
|
const right: T[] = []
|
||||||
|
for (const item of arr) {
|
||||||
|
fn(item) ? left.push(item) : right.push(item)
|
||||||
|
}
|
||||||
|
return [left, right]
|
||||||
|
}
|
||||||
|
@ -17,19 +17,31 @@ export interface Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Rules {
|
export interface Rules {
|
||||||
rules: { name: string, payload: string }[]
|
rules: Rule[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Rule {
|
||||||
|
type: string
|
||||||
|
payload: string
|
||||||
|
proxy: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Proxies {
|
export interface Proxies {
|
||||||
proxies: {
|
proxies: {
|
||||||
[key: string]: Proxy
|
[key: string]: Proxy | Group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Proxy {
|
export interface Proxy {
|
||||||
type: 'Direct' | 'Selector' | 'Reject' | 'URLTest' | 'Shadowsocks' | 'Vmess' | 'Socks' | 'Fallback'
|
name: string
|
||||||
now?: string
|
type: 'Direct' | 'Reject' | 'Shadowsocks' | 'Vmess' | 'Socks' | 'Http'
|
||||||
all?: string[]
|
}
|
||||||
|
|
||||||
|
export interface Group {
|
||||||
|
name: string
|
||||||
|
type: 'Selector' | 'URLTest' | 'Fallback'
|
||||||
|
now: string
|
||||||
|
all: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getConfig () {
|
export async function getConfig () {
|
||||||
@ -66,7 +78,7 @@ export async function getProxyDelay (name: string) {
|
|||||||
const req = await getInstance()
|
const req = await getInstance()
|
||||||
return req.get<{ delay: number }>(`proxies/${name}/delay`, {
|
return req.get<{ delay: number }>(`proxies/${name}/delay`, {
|
||||||
params: {
|
params: {
|
||||||
timeout: 20000,
|
timeout: 5000,
|
||||||
url: 'http://www.gstatic.com/generate_204'
|
url: 'http://www.gstatic.com/generate_204'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -74,7 +86,7 @@ export async function getProxyDelay (name: string) {
|
|||||||
|
|
||||||
export async function changeProxySelected (name: string, select: string) {
|
export async function changeProxySelected (name: string, select: string) {
|
||||||
const req = await getInstance()
|
const req = await getInstance()
|
||||||
return req.get<void>(`proxies/${name}`, { data: { name: select } })
|
return req.put<void>(`proxies/${name}`, { name: select })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getInstance () {
|
export async function getInstance () {
|
||||||
@ -98,8 +110,8 @@ export async function getInstance () {
|
|||||||
|
|
||||||
export async function getExternalControllerConfig () {
|
export async function getExternalControllerConfig () {
|
||||||
if (isClashX()) {
|
if (isClashX()) {
|
||||||
await rootStores.config.fetchAndParseConfig()
|
await rootStores.store.fetchAndParseConfig()
|
||||||
const general = rootStores.config.config.general
|
const general = rootStores.store.config.general
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hostname: general.externalControllerAddr,
|
hostname: general.externalControllerAddr,
|
||||||
|
@ -14,7 +14,7 @@ export interface BaseRouterProps extends RouteComponentProps<any>, BaseProps {}
|
|||||||
export interface BaseProps extends BaseComponentProps {
|
export interface BaseProps extends BaseComponentProps {
|
||||||
styles?: any
|
styles?: any
|
||||||
router?: RouterStore
|
router?: RouterStore
|
||||||
config?: ConfigStore
|
store?: ConfigStore
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseComponentProps {
|
export interface BaseComponentProps {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Proxy, ProxyGroup } from './Proxy'
|
import { Proxy, ProxyGroup } from './Proxy'
|
||||||
import { Rule } from './Rule'
|
import { Rule } from './Rule'
|
||||||
|
import * as API from '@lib/request'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clash config
|
* clash config
|
||||||
@ -62,3 +63,45 @@ export interface Config {
|
|||||||
rules?: Rule[]
|
rules?: Rule[]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Data {
|
||||||
|
|
||||||
|
general?: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http proxy port
|
||||||
|
*/
|
||||||
|
port?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* socks proxy port
|
||||||
|
*/
|
||||||
|
socksPort?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redir proxy port
|
||||||
|
*/
|
||||||
|
redirPort?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* proxy is allow lan
|
||||||
|
*/
|
||||||
|
allowLan?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clash proxy mode
|
||||||
|
*/
|
||||||
|
mode?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clash tty log level
|
||||||
|
*/
|
||||||
|
logLevel?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy?: API.Proxy[]
|
||||||
|
|
||||||
|
proxyGroup?: API.Group[]
|
||||||
|
|
||||||
|
rules?: API.Rule[]
|
||||||
|
}
|
||||||
|
@ -2,8 +2,8 @@ import { observable, action, runInAction } from 'mobx'
|
|||||||
import * as yaml from 'yaml'
|
import * as yaml from 'yaml'
|
||||||
import * as Models from '@models'
|
import * as Models from '@models'
|
||||||
import { jsBridge } from '@lib/jsBridge'
|
import { jsBridge } from '@lib/jsBridge'
|
||||||
import { getConfig } from '@lib/request'
|
import * as API from '@lib/request'
|
||||||
import { getLocalStorageItem } from '@lib/helper'
|
import { getLocalStorageItem, partition } from '@lib/helper'
|
||||||
|
|
||||||
export class ConfigStore {
|
export class ConfigStore {
|
||||||
|
|
||||||
@ -15,19 +15,47 @@ export class ConfigStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
public state: 'pending' | 'ok' | 'error' = 'pending'
|
data: Models.Data = {
|
||||||
|
general: {},
|
||||||
|
proxy: [],
|
||||||
|
proxyGroup: [],
|
||||||
|
rules: []
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async fetchData () {
|
||||||
|
const [{ data: general }, rawProxies, rules] = await Promise.all([API.getConfig(), API.getProxies(), API.getRules()])
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.data.general = {
|
||||||
|
port: general.port,
|
||||||
|
socksPort: general['socket-port'],
|
||||||
|
redirPort: general['redir-port'],
|
||||||
|
mode: general.mode,
|
||||||
|
logLevel: general['log-level']
|
||||||
|
}
|
||||||
|
|
||||||
|
const policyGroup = new Set(['Selector', 'URLTest', 'Fallback'])
|
||||||
|
const unUsedProxy = new Set(['DIRECT', 'REJECT', 'GLOBAL'])
|
||||||
|
const proxies = Object.keys(rawProxies.data.proxies)
|
||||||
|
.filter(key => !unUsedProxy.has(key))
|
||||||
|
.map(key => ({ ...rawProxies.data.proxies[key], name: key }))
|
||||||
|
const [proxy, groups] = partition(proxies, proxy => !policyGroup.has(proxy.type))
|
||||||
|
this.data.proxy = proxy as API.Proxy[]
|
||||||
|
this.data.proxyGroup = groups as API.Group[]
|
||||||
|
|
||||||
|
this.data.rules = rules.data.rules
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async fetchAndParseConfig () {
|
async fetchAndParseConfig () {
|
||||||
this.state = 'pending'
|
|
||||||
|
|
||||||
const rawConfig = await jsBridge.readConfigString()
|
const rawConfig = await jsBridge.readConfigString()
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
// emit error when config is empty
|
// emit error when config is empty
|
||||||
// because read config might be error
|
// because read config might be error
|
||||||
if (!rawConfig) {
|
if (!rawConfig) {
|
||||||
this.state = 'error'
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,13 +93,12 @@ export class ConfigStore {
|
|||||||
proxyGroup,
|
proxyGroup,
|
||||||
rules: rule || []
|
rules: rule || []
|
||||||
}
|
}
|
||||||
this.state = 'ok'
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async fetchConfig () {
|
async fetchConfig () {
|
||||||
const { data: config } = await getConfig()
|
const { data: config } = await API.getConfig()
|
||||||
this.config = {
|
this.config = {
|
||||||
general: {
|
general: {
|
||||||
port: config.port,
|
port: config.port,
|
||||||
|
@ -18,4 +18,5 @@ $color-white: #fff;
|
|||||||
$color-green: #67c23a;
|
$color-green: #67c23a;
|
||||||
$color-orange: #e6a23c;
|
$color-orange: #e6a23c;
|
||||||
$color-red: #f56c6c;
|
$color-red: #f56c6c;
|
||||||
|
$color-black-light: #546b87;
|
||||||
$color-black: #000;
|
$color-black: #000;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user