mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 14:01:56 +08:00
Chore: add more strictly eslint
This commit is contained in:
parent
5ff1742361
commit
df0bfb5e10
@ -1,3 +1,17 @@
|
|||||||
extends:
|
extends:
|
||||||
|
- standard-with-typescript
|
||||||
- react-app
|
- react-app
|
||||||
parser: '@typescript-eslint/parser'
|
parser: '@typescript-eslint/parser'
|
||||||
|
parserOptions:
|
||||||
|
project: './tsconfig.json'
|
||||||
|
rules:
|
||||||
|
comma-dangle: [error, always-multiline]
|
||||||
|
'@typescript-eslint/indent': [error, 4]
|
||||||
|
'@typescript-eslint/explicit-function-return-type': off
|
||||||
|
'@typescript-eslint/restrict-template-expressions': off
|
||||||
|
'@typescript-eslint/strict-boolean-expressions': off
|
||||||
|
'@typescript-eslint/no-non-null-assertion': off
|
||||||
|
'@typescript-eslint/consistent-type-assertions': off
|
||||||
|
'@typescript-eslint/promise-function-async': off
|
||||||
|
'@typescript-eslint/no-floating-promises': off
|
||||||
|
'@typescript-eslint/no-invalid-void-type': off
|
||||||
|
@ -39,9 +39,12 @@
|
|||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"eslint": "^7.29.0",
|
"eslint": "^7.29.0",
|
||||||
"eslint-config-react-app": "^6.0.0",
|
"eslint-config-react-app": "^6.0.0",
|
||||||
|
"eslint-config-standard-with-typescript": "^20.0.0",
|
||||||
"eslint-plugin-flowtype": "^5.7.2",
|
"eslint-plugin-flowtype": "^5.7.2",
|
||||||
"eslint-plugin-import": "^2.23.4",
|
"eslint-plugin-import": "^2.23.4",
|
||||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^5.1.0",
|
||||||
"eslint-plugin-react": "^7.24.0",
|
"eslint-plugin-react": "^7.24.0",
|
||||||
"eslint-plugin-react-hooks": "^4.2.0",
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
"sass": "^1.35.1",
|
"sass": "^1.35.1",
|
||||||
|
@ -14,7 +14,7 @@ const iconMap = {
|
|||||||
success: 'check',
|
success: 'check',
|
||||||
info: 'info',
|
info: 'info',
|
||||||
warning: 'info',
|
warning: 'info',
|
||||||
error: 'close'
|
error: 'close',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Alert (props: AlertProps) {
|
export function Alert (props: AlertProps) {
|
||||||
|
@ -10,7 +10,7 @@ export interface ButtonSelectOptions<T = string> {
|
|||||||
|
|
||||||
export interface ButtonSelectProps<T = string> extends BaseComponentProps {
|
export interface ButtonSelectProps<T = string> extends BaseComponentProps {
|
||||||
// options
|
// options
|
||||||
options: ButtonSelectOptions<T>[]
|
options: Array<ButtonSelectOptions<T>>
|
||||||
|
|
||||||
// active value
|
// active value
|
||||||
value: T
|
value: T
|
||||||
|
@ -26,7 +26,7 @@ export function Input (props: InputProps) {
|
|||||||
type = 'text',
|
type = 'text',
|
||||||
disabled = false,
|
disabled = false,
|
||||||
onChange = noop,
|
onChange = noop,
|
||||||
onBlur = noop
|
onBlur = noop,
|
||||||
} = props
|
} = props
|
||||||
const classname = classnames('input', `text-${align}`, { 'focus:shadow-none': inside }, className)
|
const classname = classnames('input', `text-${align}`, { 'focus:shadow-none': inside }, className)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const TYPE_ICON_MAP = {
|
|||||||
info: 'info',
|
info: 'info',
|
||||||
success: 'check',
|
success: 'check',
|
||||||
warning: 'info-o',
|
warning: 'info-o',
|
||||||
error: 'close'
|
error: 'close',
|
||||||
}
|
}
|
||||||
|
|
||||||
type NoticeType = 'success' | 'info' | 'warning' | 'error'
|
type NoticeType = 'success' | 'info' | 'warning' | 'error'
|
||||||
@ -38,7 +38,7 @@ export function Message (props: MessageProps) {
|
|||||||
icon = <Icon type="info" size={16} />,
|
icon = <Icon type="info" size={16} />,
|
||||||
content = '',
|
content = '',
|
||||||
type = 'info',
|
type = 'info',
|
||||||
duration = 1500
|
duration = 1500,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const { visible, show, hide } = useVisible()
|
const { visible, show, hide } = useVisible()
|
||||||
@ -85,7 +85,7 @@ export function showMessage (args: ArgsProps) {
|
|||||||
content,
|
content,
|
||||||
removeComponent,
|
removeComponent,
|
||||||
duration,
|
duration,
|
||||||
onClose
|
onClose,
|
||||||
}
|
}
|
||||||
|
|
||||||
render(<Message {...props} />, container)
|
render(<Message {...props} />, container)
|
||||||
@ -94,23 +94,23 @@ export function showMessage (args: ArgsProps) {
|
|||||||
export const info = (
|
export const info = (
|
||||||
content: string,
|
content: string,
|
||||||
duration?: number,
|
duration?: number,
|
||||||
onClose?: typeof noop
|
onClose?: typeof noop,
|
||||||
) => showMessage({ type: 'info', content, duration, onClose })
|
) => showMessage({ type: 'info', content, duration, onClose })
|
||||||
|
|
||||||
export const success = (
|
export const success = (
|
||||||
content: string,
|
content: string,
|
||||||
duration?: number,
|
duration?: number,
|
||||||
onClose?: typeof noop
|
onClose?: typeof noop,
|
||||||
) => showMessage({ type: 'success', content, duration, onClose })
|
) => showMessage({ type: 'success', content, duration, onClose })
|
||||||
|
|
||||||
export const warning = (
|
export const warning = (
|
||||||
content: string,
|
content: string,
|
||||||
duration?: number,
|
duration?: number,
|
||||||
onClose?: typeof noop
|
onClose?: typeof noop,
|
||||||
) => showMessage({ type: 'warning', content, duration, onClose })
|
) => showMessage({ type: 'warning', content, duration, onClose })
|
||||||
|
|
||||||
export const error = (
|
export const error = (
|
||||||
content: string,
|
content: string,
|
||||||
duration?: number,
|
duration?: number,
|
||||||
onClose?: typeof noop
|
onClose?: typeof noop,
|
||||||
) => showMessage({ type: 'error', content, duration, onClose })
|
) => showMessage({ type: 'error', content, duration, onClose })
|
||||||
|
@ -45,7 +45,7 @@ export function Modal (props: ModalProps) {
|
|||||||
bodyStyle,
|
bodyStyle,
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
children
|
children,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const { translation } = useI18n()
|
const { translation } = useI18n()
|
||||||
|
@ -23,18 +23,18 @@ interface SelectProps extends BaseComponentProps {
|
|||||||
export function Select (props: SelectProps) {
|
export function Select (props: SelectProps) {
|
||||||
const { value, onSelect, children, className: cn, style } = props
|
const { value, onSelect, children, className: cn, style } = props
|
||||||
|
|
||||||
const portalRef = useRef<HTMLDivElement>()
|
const portalRef = useRef<HTMLDivElement>(document.createElement('div'))
|
||||||
const attachmentRef = useRef<HTMLDivElement>(null)
|
const attachmentRef = useRef<HTMLDivElement>(null)
|
||||||
const targetRef = useRef<HTMLDivElement>(null)
|
const targetRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
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(() => {
|
||||||
if (targetRef.current) {
|
if (targetRef.current != null) {
|
||||||
const targetRectInfo = targetRef.current.getBoundingClientRect()
|
const targetRectInfo = targetRef.current.getBoundingClientRect()
|
||||||
return {
|
return {
|
||||||
top: Math.floor(targetRectInfo.top) - 10,
|
top: Math.floor(targetRectInfo.top) - 10,
|
||||||
left: Math.floor(targetRectInfo.left) - 10
|
left: Math.floor(targetRectInfo.left) - 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
@ -49,23 +49,17 @@ export function Select (props: SelectProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
const current = portalRef.current
|
||||||
|
document.body.appendChild(current)
|
||||||
document.addEventListener('click', handleGlobalClick, true)
|
document.addEventListener('click', handleGlobalClick, true)
|
||||||
return () => {
|
return () => {
|
||||||
document.addEventListener('click', handleGlobalClick, true)
|
document.addEventListener('click', handleGlobalClick, true)
|
||||||
if (portalRef.current) {
|
document.body.removeChild(current)
|
||||||
document.body.removeChild(portalRef.current)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
function handleShowDropList () {
|
function handleShowDropList () {
|
||||||
if (!hasCreateDropList) {
|
if (!hasCreateDropList) {
|
||||||
if (!portalRef.current) {
|
|
||||||
// create container element
|
|
||||||
const container = document.createElement('div')
|
|
||||||
document.body.appendChild(container)
|
|
||||||
portalRef.current = container
|
|
||||||
}
|
|
||||||
setHasCreateDropList(true)
|
setHasCreateDropList(true)
|
||||||
}
|
}
|
||||||
setShowDropDownList(true)
|
setShowDropDownList(true)
|
||||||
@ -100,9 +94,9 @@ export function Select (props: SelectProps) {
|
|||||||
onClick: (e: React.MouseEvent<HTMLLIElement>) => {
|
onClick: (e: React.MouseEvent<HTMLLIElement>) => {
|
||||||
onSelect?.(child.props.value, e)
|
onSelect?.(child.props.value, e)
|
||||||
setShowDropDownList(false)
|
setShowDropDownList(false)
|
||||||
rawOnClickEvent && rawOnClickEvent(e)
|
rawOnClickEvent?.(e)
|
||||||
},
|
},
|
||||||
className
|
className,
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
}, [children, value, onSelect])
|
}, [children, value, onSelect])
|
||||||
@ -131,7 +125,7 @@ export function Select (props: SelectProps) {
|
|||||||
<Icon type="triangle-down" />
|
<Icon type="triangle-down" />
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
hasCreateDropList && createPortal(dropDownList, portalRef?.current!)
|
hasCreateDropList && createPortal(dropDownList, portalRef.current)
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -25,7 +25,7 @@ export default function App () {
|
|||||||
{ 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 },
|
||||||
{ path: '/connections', name: 'Connections', component: Connections, noMobile: true },
|
{ path: '/connections', name: 'Connections', component: Connections, noMobile: true },
|
||||||
{ path: '/settings', name: 'Settings', component: Settings }
|
{ path: '/settings', name: 'Settings', component: Settings },
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -36,7 +36,7 @@ export default function App () {
|
|||||||
<Route exact path="/" component={() => <Redirect to="/proxies"/>} />
|
<Route exact path="/" component={() => <Redirect to="/proxies"/>} />
|
||||||
{
|
{
|
||||||
routes.map(
|
routes.map(
|
||||||
route => <Route exact={false} path={route.path} key={route.path} component={route.component} />
|
route => <Route exact={false} path={route.path} key={route.path} component={route.component} />,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Switch>
|
</Switch>
|
||||||
|
@ -34,7 +34,7 @@ export function Devices (props: DevicesProps) {
|
|||||||
onClick={() => handleSelected(device.label)}>
|
onClick={() => handleSelected(device.label)}>
|
||||||
{ device.label } ({ device.number })
|
{ device.label } ({ device.number })
|
||||||
</div>
|
</div>
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,7 +47,7 @@ interface ITableInstance<D extends object = {}> extends
|
|||||||
TableInstance<D>,
|
TableInstance<D>,
|
||||||
UseFiltersInstanceProps<D> {}
|
UseFiltersInstanceProps<D> {}
|
||||||
|
|
||||||
function formatTraffic(num: number) {
|
function formatTraffic (num: number) {
|
||||||
const s = ['B', 'KB', 'MB', 'GB', 'TB']
|
const s = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||||
let idx = 0
|
let idx = 0
|
||||||
while (~~(num / 1024) && idx < s.length) {
|
while (~~(num / 1024) && idx < s.length) {
|
||||||
@ -58,7 +58,7 @@ function formatTraffic(num: number) {
|
|||||||
return `${idx === 0 ? num : num.toFixed(2)} ${s[idx]}`
|
return `${idx === 0 ? num : num.toFixed(2)} ${s[idx]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatSpeed(upload: number, download: number) {
|
function formatSpeed (upload: number, download: number) {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case upload === 0 && download === 0:
|
case upload === 0 && download === 0:
|
||||||
return '-'
|
return '-'
|
||||||
@ -89,7 +89,7 @@ interface formatConnection {
|
|||||||
completed: boolean
|
completed: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Connections() {
|
export default function Connections () {
|
||||||
const { translation, lang } = useI18n()
|
const { translation, lang } = useI18n()
|
||||||
const t = useMemo(() => translation('Connections').t, [translation])
|
const t = useMemo(() => translation('Connections').t, [translation])
|
||||||
const connStreamReader = useConnectionStreamReader()
|
const connStreamReader = useConnectionStreamReader()
|
||||||
@ -98,12 +98,12 @@ export default function Connections() {
|
|||||||
// total
|
// total
|
||||||
const [traffic, setTraffic] = useObject({
|
const [traffic, setTraffic] = useObject({
|
||||||
uploadTotal: 0,
|
uploadTotal: 0,
|
||||||
downloadTotal: 0
|
downloadTotal: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
// close all connections
|
// close all connections
|
||||||
const { visible, show, hide } = useVisible()
|
const { visible, show, hide } = useVisible()
|
||||||
function handleCloseConnections() {
|
function handleCloseConnections () {
|
||||||
client.closeAllConnections().finally(() => hide())
|
client.closeAllConnections().finally(() => hide())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,8 +122,8 @@ export default function Connections() {
|
|||||||
type: c.metadata.type,
|
type: c.metadata.type,
|
||||||
network: c.metadata.network.toUpperCase(),
|
network: c.metadata.network.toUpperCase(),
|
||||||
speed: { upload: c.uploadSpeed, download: c.downloadSpeed },
|
speed: { upload: c.uploadSpeed, download: c.downloadSpeed },
|
||||||
completed: !!c.completed
|
completed: !!c.completed,
|
||||||
})
|
}),
|
||||||
), [connections])
|
), [connections])
|
||||||
const devices = useMemo(() => {
|
const devices = useMemo(() => {
|
||||||
const gb = groupBy(connections, 'metadata.sourceIP')
|
const gb = groupBy(connections, 'metadata.sourceIP')
|
||||||
@ -133,7 +133,7 @@ export default function Connections() {
|
|||||||
// table
|
// table
|
||||||
const tableRef = useRef<HTMLDivElement>(null)
|
const tableRef = useRef<HTMLDivElement>(null)
|
||||||
const { x: scrollX } = useScroll(tableRef)
|
const { x: scrollX } = useScroll(tableRef)
|
||||||
const columns: TableColumnOption<formatConnection>[] = useMemo(() => [
|
const columns: Array<TableColumnOption<formatConnection>> = useMemo(() => [
|
||||||
{ Header: t(`columns.${Columns.Host}`), accessor: Columns.Host, minWidth: 260, width: 260 },
|
{ Header: t(`columns.${Columns.Host}`), accessor: Columns.Host, minWidth: 260, width: 260 },
|
||||||
{ Header: t(`columns.${Columns.Network}`), accessor: Columns.Network, minWidth: 80, width: 80 },
|
{ Header: t(`columns.${Columns.Network}`), accessor: Columns.Network, minWidth: 80, width: 80 },
|
||||||
{ Header: t(`columns.${Columns.Type}`), accessor: Columns.Type, minWidth: 120, width: 120 },
|
{ Header: t(`columns.${Columns.Type}`), accessor: Columns.Type, minWidth: 120, width: 120 },
|
||||||
@ -142,31 +142,32 @@ export default function Connections() {
|
|||||||
{
|
{
|
||||||
id: Columns.Speed,
|
id: Columns.Speed,
|
||||||
Header: t(`columns.${Columns.Speed}`),
|
Header: t(`columns.${Columns.Speed}`),
|
||||||
accessor(originalRow: formatConnection) {
|
accessor (originalRow: formatConnection) {
|
||||||
return [originalRow.speed.upload, originalRow.speed.download]
|
return [originalRow.speed.upload, originalRow.speed.download]
|
||||||
},
|
},
|
||||||
sortType(rowA, rowB) {
|
sortType (rowA, rowB) {
|
||||||
const speedA = rowA.original.speed
|
const speedA = rowA.original.speed
|
||||||
const speedB = rowB.original.speed
|
const speedB = rowB.original.speed
|
||||||
return speedA.download === speedB.download
|
return speedA.download === speedB.download
|
||||||
? speedA.upload - speedB.upload
|
? speedA.upload - speedB.upload
|
||||||
: speedA.download - speedB.download
|
: speedA.download - speedB.download
|
||||||
},
|
},
|
||||||
minWidth: 200, width: 200,
|
minWidth: 200,
|
||||||
sortDescFirst: true
|
width: 200,
|
||||||
|
sortDescFirst: true,
|
||||||
},
|
},
|
||||||
{ Header: t(`columns.${Columns.Upload}`), accessor: Columns.Upload, minWidth: 100, width: 100, sortDescFirst: true },
|
{ Header: t(`columns.${Columns.Upload}`), accessor: Columns.Upload, minWidth: 100, width: 100, sortDescFirst: true },
|
||||||
{ Header: t(`columns.${Columns.Download}`), accessor: Columns.Download, minWidth: 100, width: 100, sortDescFirst: true },
|
{ Header: t(`columns.${Columns.Download}`), accessor: Columns.Download, minWidth: 100, width: 100, sortDescFirst: true },
|
||||||
{ Header: t(`columns.${Columns.SourceIP}`), accessor: Columns.SourceIP, minWidth: 140, width: 140 },
|
{ Header: t(`columns.${Columns.SourceIP}`), accessor: Columns.SourceIP, minWidth: 140, width: 140 },
|
||||||
{ Header: t(`columns.${Columns.Time}`), accessor: Columns.Time, minWidth: 120, width: 120, sortType(rowA, rowB) { return rowB.original.time - rowA.original.time } },
|
{ Header: t(`columns.${Columns.Time}`), accessor: Columns.Time, minWidth: 120, width: 120, sortType (rowA, rowB) { return rowB.original.time - rowA.original.time } },
|
||||||
] as TableColumnOption<formatConnection>[], [t])
|
] as Array<TableColumnOption<formatConnection>>, [t])
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
function handleConnection(snapshots: API.Snapshot[]) {
|
function handleConnection (snapshots: API.Snapshot[]) {
|
||||||
for (const snapshot of snapshots) {
|
for (const snapshot of snapshots) {
|
||||||
setTraffic({
|
setTraffic({
|
||||||
uploadTotal: snapshot.uploadTotal,
|
uploadTotal: snapshot.uploadTotal,
|
||||||
downloadTotal: snapshot.downloadTotal
|
downloadTotal: snapshot.downloadTotal,
|
||||||
})
|
})
|
||||||
|
|
||||||
feed(snapshot.connections)
|
feed(snapshot.connections)
|
||||||
@ -186,19 +187,19 @@ export default function Connections() {
|
|||||||
headerGroups,
|
headerGroups,
|
||||||
rows,
|
rows,
|
||||||
prepareRow,
|
prepareRow,
|
||||||
setFilter
|
setFilter,
|
||||||
} = useTable(
|
} = useTable(
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
data,
|
data,
|
||||||
autoResetSortBy: false,
|
autoResetSortBy: false,
|
||||||
autoResetFilters: false,
|
autoResetFilters: false,
|
||||||
initialState: { sortBy: [{ id: Columns.Time, desc: false }] }
|
initialState: { sortBy: [{ id: Columns.Time, desc: false }] },
|
||||||
} as ITableOptions<formatConnection>,
|
} as ITableOptions<formatConnection>,
|
||||||
useResizeColumns,
|
useResizeColumns,
|
||||||
useBlockLayout,
|
useBlockLayout,
|
||||||
useFilters,
|
useFilters,
|
||||||
useSortBy
|
useSortBy,
|
||||||
) as ITableInstance<formatConnection>
|
) as ITableInstance<formatConnection>
|
||||||
const headerGroup = useMemo(() => headerGroups[0], [headerGroups])
|
const headerGroup = useMemo(() => headerGroups[0], [headerGroups])
|
||||||
const renderCell = useCallback(function (cell: Cell<formatConnection>) {
|
const renderCell = useCallback(function (cell: Cell<formatConnection>) {
|
||||||
@ -244,7 +245,7 @@ export default function Connections() {
|
|||||||
{...realColumn.getHeaderProps()}
|
{...realColumn.getHeaderProps()}
|
||||||
className={classnames('connections-th', {
|
className={classnames('connections-th', {
|
||||||
resizing: realColumn.isResizing,
|
resizing: realColumn.isResizing,
|
||||||
fixed: scrollX > 0 && realColumn.id === Columns.Host
|
fixed: scrollX > 0 && realColumn.id === Columns.Host,
|
||||||
})}
|
})}
|
||||||
key={id}>
|
key={id}>
|
||||||
<div {...realColumn.getSortByToggleProps()}>
|
<div {...realColumn.getSortByToggleProps()}>
|
||||||
@ -275,7 +276,7 @@ export default function Connections() {
|
|||||||
const classname = classnames(
|
const classname = classnames(
|
||||||
'connections-block',
|
'connections-block',
|
||||||
{ 'text-center': shouldCenter.has(cell.column.id), completed: row.original.completed },
|
{ 'text-center': shouldCenter.has(cell.column.id), completed: row.original.completed },
|
||||||
{ fixed: scrollX > 0 && cell.column.id === Columns.Host }
|
{ fixed: scrollX > 0 && cell.column.id === Columns.Host },
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<div {...cell.getCellProps()} className={classname} key={cell.column.id}>
|
<div {...cell.getCellProps()} className={classname} key={cell.column.id}>
|
||||||
|
@ -9,7 +9,7 @@ class Store {
|
|||||||
|
|
||||||
appendToSet (connections: API.Connections[]) {
|
appendToSet (connections: API.Connections[]) {
|
||||||
const mapping = connections.reduce(
|
const mapping = connections.reduce(
|
||||||
(map, c) => map.set(c.id, c), new Map<string, API.Connections>()
|
(map, c) => map.set(c.id, c), new Map<string, API.Connections>(),
|
||||||
)
|
)
|
||||||
|
|
||||||
for (const id of this.connections.keys()) {
|
for (const id of this.connections.keys()) {
|
||||||
@ -18,7 +18,7 @@ class Store {
|
|||||||
this.connections.delete(id)
|
this.connections.delete(id)
|
||||||
} else {
|
} else {
|
||||||
const connection = this.connections.get(id)
|
const connection = this.connections.get(id)
|
||||||
if (connection) {
|
if (connection != null) {
|
||||||
connection.completed = true
|
connection.completed = true
|
||||||
connection.uploadSpeed = 0
|
connection.uploadSpeed = 0
|
||||||
connection.downloadSpeed = 0
|
connection.downloadSpeed = 0
|
||||||
|
@ -15,7 +15,7 @@ export default function ExternalController () {
|
|||||||
const [value, set] = useObject({
|
const [value, set] = useObject({
|
||||||
hostname: '',
|
hostname: '',
|
||||||
port: '',
|
port: '',
|
||||||
secret: ''
|
secret: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -15,7 +15,7 @@ export default function Logs () {
|
|||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const ul = listRef.current
|
const ul = listRef.current
|
||||||
if (ul) {
|
if (ul != null) {
|
||||||
ul.scrollTop = ul.scrollHeight
|
ul.scrollTop = ul.scrollHeight
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -26,7 +26,7 @@ export default function Logs () {
|
|||||||
setLogs(logsRef.current)
|
setLogs(logsRef.current)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logsStreamReader) {
|
if (logsStreamReader != null) {
|
||||||
logsStreamReader.subscribe('data', handleLog)
|
logsStreamReader.subscribe('data', handleLog)
|
||||||
logsRef.current = logsStreamReader.buffer()
|
logsRef.current = logsStreamReader.buffer()
|
||||||
setLogs(logsRef.current)
|
setLogs(logsRef.current)
|
||||||
@ -47,7 +47,7 @@ export default function Logs () {
|
|||||||
<span className="mr-4 text-gray-400 text-opacity-90">{ dayjs(log.time).format('YYYY-MM-DD HH:mm:ss') }</span>
|
<span className="mr-4 text-gray-400 text-opacity-90">{ dayjs(log.time).format('YYYY-MM-DD HH:mm:ss') }</span>
|
||||||
<span>[{ log.type }] { log.payload }</span>
|
<span>[{ log.type }] { log.payload }</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -9,10 +9,10 @@ export default function Overview () {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
opacity: 0.3
|
opacity: 0.3,
|
||||||
}}>
|
}}>
|
||||||
<img src={logo} alt="Logo" style={{
|
<img src={logo} alt="Logo" style={{
|
||||||
width: 200
|
width: 200,
|
||||||
}}/>
|
}}/>
|
||||||
|
|
||||||
<h1 style={{ color: '#54759A', marginTop: 20 }}>Coming Soon...</h1>
|
<h1 style={{ color: '#54759A', marginTop: 20 }}>Coming Soon...</h1>
|
||||||
|
@ -28,9 +28,7 @@ export function Group (props: GroupProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const id of list) {
|
await Promise.all(list.map(id => client.closeConnection(id)))
|
||||||
client.closeConnection(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +24,12 @@ export function Provider (props: ProvidersProps) {
|
|||||||
|
|
||||||
function handleHealthChech () {
|
function handleHealthChech () {
|
||||||
show()
|
show()
|
||||||
client.healthCheckProvider(provider.name).then(() => update()).finally(() => hide())
|
client.healthCheckProvider(provider.name).then(async () => await update()).finally(() => hide())
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUpdate () {
|
function handleUpdate () {
|
||||||
show()
|
show()
|
||||||
client.updateProvider(provider.name).then(() => update()).finally(() => hide())
|
client.updateProvider(provider.name).then(async () => await update()).finally(() => hide())
|
||||||
}
|
}
|
||||||
|
|
||||||
const proxies = useMemo(() => {
|
const proxies = useMemo(() => {
|
||||||
|
@ -18,7 +18,7 @@ const TagColors = {
|
|||||||
'#909399': 0,
|
'#909399': 0,
|
||||||
'#00c520': 260,
|
'#00c520': 260,
|
||||||
'#ff9a28': 600,
|
'#ff9a28': 600,
|
||||||
'#ff3e5e': Infinity
|
'#ff3e5e': Infinity,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Proxy (props: ProxyProps) {
|
export function Proxy (props: ProxyProps) {
|
||||||
@ -42,7 +42,7 @@ export function Proxy (props: ProxyProps) {
|
|||||||
const validDelay = result.isErr() ? 0 : result.value
|
const validDelay = result.isErr() ? 0 : result.value
|
||||||
set(draft => {
|
set(draft => {
|
||||||
const proxy = draft.proxies.find(p => p.name === config.name)
|
const proxy = draft.proxies.find(p => p.name === config.name)
|
||||||
if (proxy) {
|
if (proxy != null) {
|
||||||
proxy.history.push({ time: Date.now().toString(), delay: validDelay })
|
proxy.history.push({ time: Date.now().toString(), delay: validDelay })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -50,20 +50,21 @@ export function Proxy (props: ProxyProps) {
|
|||||||
|
|
||||||
const delay = useMemo(
|
const delay = useMemo(
|
||||||
() => config.history?.length ? config.history.slice(-1)[0].delay : 0,
|
() => config.history?.length ? config.history.slice(-1)[0].delay : 0,
|
||||||
[config]
|
[config],
|
||||||
)
|
)
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
EE.subscribe(Action.SPEED_NOTIFY, speedTest)
|
const handler = () => { speedTest() }
|
||||||
return () => EE.unsubscribe(Action.SPEED_NOTIFY, speedTest)
|
EE.subscribe(Action.SPEED_NOTIFY, handler)
|
||||||
|
return () => EE.unsubscribe(Action.SPEED_NOTIFY, handler)
|
||||||
}, [speedTest])
|
}, [speedTest])
|
||||||
|
|
||||||
const hasError = useMemo(() => delay === 0, [delay])
|
const hasError = useMemo(() => delay === 0, [delay])
|
||||||
const color = useMemo(() =>
|
const color = useMemo(
|
||||||
Object.keys(TagColors).find(
|
() => Object.keys(TagColors).find(
|
||||||
threshold => delay <= TagColors[threshold as keyof typeof TagColors]
|
threshold => delay <= TagColors[threshold as keyof typeof TagColors],
|
||||||
),
|
),
|
||||||
[delay]
|
[delay],
|
||||||
)
|
)
|
||||||
|
|
||||||
const backgroundColor = hasError ? undefined : color
|
const backgroundColor = hasError ? undefined : color
|
||||||
|
@ -17,12 +17,12 @@ enum sortType {
|
|||||||
const sortMap = {
|
const sortMap = {
|
||||||
[sortType.None]: 'sort',
|
[sortType.None]: 'sort',
|
||||||
[sortType.Asc]: 'sort-ascending',
|
[sortType.Asc]: 'sort-ascending',
|
||||||
[sortType.Desc]: 'sort-descending'
|
[sortType.Desc]: 'sort-descending',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compareDesc (a: API.Proxy, b: API.Proxy) {
|
export function compareDesc (a: API.Proxy, b: API.Proxy) {
|
||||||
const lastDelayA = a.history.length ? a.history.slice(-1)[0].delay : 0
|
const lastDelayA = (a.history.length > 0) ? a.history.slice(-1)[0].delay : 0
|
||||||
const lastDelayB = b.history.length ? b.history.slice(-1)[0].delay : 0
|
const lastDelayB = (b.history.length > 0) ? b.history.slice(-1)[0].delay : 0
|
||||||
return (lastDelayB || Number.MAX_SAFE_INTEGER) - (lastDelayA || Number.MAX_SAFE_INTEGER)
|
return (lastDelayB || Number.MAX_SAFE_INTEGER) - (lastDelayA || Number.MAX_SAFE_INTEGER)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ function ProxyGroups () {
|
|||||||
|
|
||||||
const list = useMemo(
|
const list = useMemo(
|
||||||
() => general.mode === 'global' ? [global] : groups,
|
() => general.mode === 'global' ? [global] : groups,
|
||||||
[general, groups, global]
|
[general, groups, global],
|
||||||
)
|
)
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
@ -100,16 +100,16 @@ function Proxies () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { current: sort, next } = useRound(
|
const { current: sort, next } = useRound(
|
||||||
[sortType.Asc, sortType.Desc, sortType.None]
|
[sortType.Asc, sortType.Desc, sortType.None],
|
||||||
)
|
)
|
||||||
const sortedProxies = useMemo(() => {
|
const sortedProxies = useMemo(() => {
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case sortType.Desc:
|
case sortType.Desc:
|
||||||
return proxies.slice().sort((a, b) => compareDesc(a, b))
|
return proxies.slice().sort((a, b) => compareDesc(a, b))
|
||||||
case sortType.Asc:
|
case sortType.Asc:
|
||||||
return proxies.slice().sort((a, b) => -1 * compareDesc(a, b))
|
return proxies.slice().sort((a, b) => -1 * compareDesc(a, b))
|
||||||
default:
|
default:
|
||||||
return proxies.slice()
|
return proxies.slice()
|
||||||
}
|
}
|
||||||
}, [sort, proxies])
|
}, [sort, proxies])
|
||||||
const handleSort = next
|
const handleSort = next
|
||||||
|
@ -23,7 +23,7 @@ export function Provider (props: ProvidersProps) {
|
|||||||
|
|
||||||
function handleUpdate () {
|
function handleUpdate () {
|
||||||
show()
|
show()
|
||||||
client.updateRuleProvider(provider.name).then(() => update()).finally(() => hide())
|
client.updateRuleProvider(provider.name).then(async () => await update()).finally(() => hide())
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateClassnames = classnames('rule-provider-icon', { 'rule-provider-loading': visible })
|
const updateClassnames = classnames('rule-provider-icon', { 'rule-provider-loading': visible })
|
||||||
|
@ -23,7 +23,7 @@ export default function Settings () {
|
|||||||
const [info, set] = useObject({
|
const [info, set] = useObject({
|
||||||
socks5ProxyPort: 7891,
|
socks5ProxyPort: 7891,
|
||||||
httpProxyPort: 7890,
|
httpProxyPort: 7890,
|
||||||
mixedProxyPort: 0
|
mixedProxyPort: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -39,12 +39,12 @@ export default function Settings () {
|
|||||||
|
|
||||||
async function handleStartAtLoginChange (state: boolean) {
|
async function handleStartAtLoginChange (state: boolean) {
|
||||||
await jsBridge?.setStartAtLogin(state)
|
await jsBridge?.setStartAtLogin(state)
|
||||||
fetchClashXData()
|
await fetchClashXData()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSetSystemProxy (state: boolean) {
|
async function handleSetSystemProxy (state: boolean) {
|
||||||
await jsBridge?.setSystemProxy(state)
|
await jsBridge?.setSystemProxy(state)
|
||||||
fetchClashXData()
|
await fetchClashXData()
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeLanguage (language: Lang) {
|
function changeLanguage (language: Lang) {
|
||||||
@ -73,7 +73,7 @@ export default function Settings () {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
hostname: externalControllerHost,
|
hostname: externalControllerHost,
|
||||||
port: externalControllerPort
|
port: externalControllerPort,
|
||||||
} = apiInfo
|
} = apiInfo
|
||||||
|
|
||||||
const { allowLan, mode } = general
|
const { allowLan, mode } = general
|
||||||
@ -86,7 +86,7 @@ export default function Settings () {
|
|||||||
const options = [
|
const options = [
|
||||||
{ label: t('values.global'), value: 'Global' },
|
{ label: t('values.global'), value: 'Global' },
|
||||||
{ label: t('values.rules'), value: 'Rule' },
|
{ label: t('values.rules'), value: 'Rule' },
|
||||||
{ label: t('values.direct'), value: 'Direct' }
|
{ label: t('values.direct'), value: 'Direct' },
|
||||||
]
|
]
|
||||||
if (premium) {
|
if (premium) {
|
||||||
options.push({ label: t('values.script'), value: 'Script' })
|
options.push({ label: t('values.script'), value: 'Script' })
|
||||||
|
@ -7,12 +7,12 @@ import logo from '@assets/logo.png'
|
|||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
routes: {
|
routes: Array<{
|
||||||
path: string
|
path: string
|
||||||
name: string
|
name: string
|
||||||
noMobile?: boolean
|
noMobile?: boolean
|
||||||
exact?: boolean
|
exact?: boolean
|
||||||
}[]
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Sidebar (props: SidebarProps) {
|
export default function Sidebar (props: SidebarProps) {
|
||||||
@ -27,7 +27,7 @@ export default function Sidebar (props: SidebarProps) {
|
|||||||
<li className={classnames('item', { 'no-mobile': noMobile })} key={name}>
|
<li className={classnames('item', { 'no-mobile': noMobile })} key={name}>
|
||||||
<NavLink to={path} activeClassName="active" exact={!!exact}>{ t(name) }</NavLink>
|
<NavLink to={path} activeClassName="active" exact={!!exact}>{ t(name) }</NavLink>
|
||||||
</li>
|
</li>
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -6,7 +6,7 @@ const EN = {
|
|||||||
Rules: 'Rules',
|
Rules: 'Rules',
|
||||||
Settings: 'Setting',
|
Settings: 'Setting',
|
||||||
Connections: 'Connections',
|
Connections: 'Connections',
|
||||||
Version: 'Version'
|
Version: 'Version',
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
@ -19,7 +19,7 @@ const EN = {
|
|||||||
socks5ProxyPort: 'Socks5 proxy port',
|
socks5ProxyPort: 'Socks5 proxy port',
|
||||||
httpProxyPort: 'HTTP proxy port',
|
httpProxyPort: 'HTTP proxy port',
|
||||||
mixedProxyPort: 'Mixed proxy port',
|
mixedProxyPort: 'Mixed proxy port',
|
||||||
externalController: 'External controller'
|
externalController: 'External controller',
|
||||||
},
|
},
|
||||||
values: {
|
values: {
|
||||||
cn: '中文',
|
cn: '中文',
|
||||||
@ -27,7 +27,7 @@ const EN = {
|
|||||||
global: 'Global',
|
global: 'Global',
|
||||||
rules: 'Rules',
|
rules: 'Rules',
|
||||||
direct: 'Direct',
|
direct: 'Direct',
|
||||||
script: 'Script'
|
script: 'Script',
|
||||||
},
|
},
|
||||||
versionString: 'Current ClashX is the latest version:{{version}}',
|
versionString: 'Current ClashX is the latest version:{{version}}',
|
||||||
checkUpdate: 'Check Update',
|
checkUpdate: 'Check Update',
|
||||||
@ -36,17 +36,17 @@ const EN = {
|
|||||||
note: 'Please note that modifying this configuration will only configure Dashboard. Will not modify your Clash configuration file. Please make sure that the external controller address matches the address in the Clash configuration file, otherwise, Dashboard will not be able to connect to Clash.',
|
note: 'Please note that modifying this configuration will only configure Dashboard. Will not modify your Clash configuration file. Please make sure that the external controller address matches the address in the Clash configuration file, otherwise, Dashboard will not be able to connect to Clash.',
|
||||||
host: 'Host',
|
host: 'Host',
|
||||||
port: 'Port',
|
port: 'Port',
|
||||||
secret: 'Secret'
|
secret: 'Secret',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
Logs: {
|
Logs: {
|
||||||
title: 'Logs'
|
title: 'Logs',
|
||||||
},
|
},
|
||||||
Rules: {
|
Rules: {
|
||||||
title: 'Rules',
|
title: 'Rules',
|
||||||
providerTitle: 'Providers',
|
providerTitle: 'Providers',
|
||||||
providerUpdateTime: 'Last updated at',
|
providerUpdateTime: 'Last updated at',
|
||||||
ruleCount: 'Rule count'
|
ruleCount: 'Rule count',
|
||||||
},
|
},
|
||||||
Connections: {
|
Connections: {
|
||||||
title: 'Connections',
|
title: 'Connections',
|
||||||
@ -54,14 +54,14 @@ const EN = {
|
|||||||
total: {
|
total: {
|
||||||
text: 'total',
|
text: 'total',
|
||||||
upload: 'upload',
|
upload: 'upload',
|
||||||
download: 'download'
|
download: 'download',
|
||||||
},
|
},
|
||||||
closeAll: {
|
closeAll: {
|
||||||
title: 'Warning',
|
title: 'Warning',
|
||||||
content: 'This would close all connections'
|
content: 'This would close all connections',
|
||||||
},
|
},
|
||||||
filter: {
|
filter: {
|
||||||
all: 'All'
|
all: 'All',
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
host: 'Host',
|
host: 'Host',
|
||||||
@ -73,8 +73,8 @@ const EN = {
|
|||||||
speed: 'Speed',
|
speed: 'Speed',
|
||||||
upload: 'Upload',
|
upload: 'Upload',
|
||||||
download: 'Download',
|
download: 'Download',
|
||||||
sourceIP: 'Source IP'
|
sourceIP: 'Source IP',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
Proxies: {
|
Proxies: {
|
||||||
title: 'Proxies',
|
title: 'Proxies',
|
||||||
@ -91,7 +91,7 @@ const EN = {
|
|||||||
'obfs-host': 'Obfs-host',
|
'obfs-host': 'Obfs-host',
|
||||||
uuid: 'UUID',
|
uuid: 'UUID',
|
||||||
alterId: 'AlterId',
|
alterId: 'AlterId',
|
||||||
tls: 'TLS'
|
tls: 'TLS',
|
||||||
},
|
},
|
||||||
groupTitle: 'Policy Group',
|
groupTitle: 'Policy Group',
|
||||||
providerTitle: 'Providers',
|
providerTitle: 'Providers',
|
||||||
@ -99,12 +99,12 @@ const EN = {
|
|||||||
expandText: 'Expand',
|
expandText: 'Expand',
|
||||||
collapseText: 'Collapse',
|
collapseText: 'Collapse',
|
||||||
speedTestText: 'Speed Test',
|
speedTestText: 'Speed Test',
|
||||||
breakConnectionsText: 'Close connections which include the group'
|
breakConnectionsText: 'Close connections which include the group',
|
||||||
},
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
ok: 'Ok',
|
ok: 'Ok',
|
||||||
cancel: 'Cancel'
|
cancel: 'Cancel',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EN
|
export default EN
|
||||||
|
@ -3,7 +3,7 @@ import zh_CN from './zh_CN'
|
|||||||
|
|
||||||
export const Language = {
|
export const Language = {
|
||||||
en_US,
|
en_US,
|
||||||
zh_CN
|
zh_CN,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Lang = keyof typeof Language
|
export type Lang = keyof typeof Language
|
||||||
|
@ -6,7 +6,7 @@ const CN = {
|
|||||||
Rules: '规则',
|
Rules: '规则',
|
||||||
Settings: '设置',
|
Settings: '设置',
|
||||||
Connections: '连接',
|
Connections: '连接',
|
||||||
Version: '版本'
|
Version: '版本',
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
title: '设置',
|
title: '设置',
|
||||||
@ -19,7 +19,7 @@ const CN = {
|
|||||||
socks5ProxyPort: 'Socks5 代理端口',
|
socks5ProxyPort: 'Socks5 代理端口',
|
||||||
httpProxyPort: 'HTTP 代理端口',
|
httpProxyPort: 'HTTP 代理端口',
|
||||||
mixedProxyPort: '混合代理端口',
|
mixedProxyPort: '混合代理端口',
|
||||||
externalController: '外部控制设置'
|
externalController: '外部控制设置',
|
||||||
},
|
},
|
||||||
values: {
|
values: {
|
||||||
cn: '中文',
|
cn: '中文',
|
||||||
@ -27,7 +27,7 @@ const CN = {
|
|||||||
global: '全局',
|
global: '全局',
|
||||||
rules: '规则',
|
rules: '规则',
|
||||||
direct: '直连',
|
direct: '直连',
|
||||||
script: '脚本'
|
script: '脚本',
|
||||||
},
|
},
|
||||||
versionString: '当前 ClashX 已是最新版本:{{version}}',
|
versionString: '当前 ClashX 已是最新版本:{{version}}',
|
||||||
checkUpdate: '检查更新',
|
checkUpdate: '检查更新',
|
||||||
@ -36,17 +36,17 @@ const CN = {
|
|||||||
note: '请注意,修改该配置项并不会修改你的 Clash 配置文件,请确认修改后的外部控制地址和 Clash 配置文件内的地址一致,否则会导致 Dashboard 无法连接。',
|
note: '请注意,修改该配置项并不会修改你的 Clash 配置文件,请确认修改后的外部控制地址和 Clash 配置文件内的地址一致,否则会导致 Dashboard 无法连接。',
|
||||||
host: 'Host',
|
host: 'Host',
|
||||||
port: '端口',
|
port: '端口',
|
||||||
secret: '密钥'
|
secret: '密钥',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
Logs: {
|
Logs: {
|
||||||
title: '日志'
|
title: '日志',
|
||||||
},
|
},
|
||||||
Rules: {
|
Rules: {
|
||||||
title: '规则',
|
title: '规则',
|
||||||
providerTitle: '规则集',
|
providerTitle: '规则集',
|
||||||
providerUpdateTime: '最后更新于',
|
providerUpdateTime: '最后更新于',
|
||||||
ruleCount: '规则条数'
|
ruleCount: '规则条数',
|
||||||
},
|
},
|
||||||
Connections: {
|
Connections: {
|
||||||
title: '连接',
|
title: '连接',
|
||||||
@ -54,14 +54,14 @@ const CN = {
|
|||||||
total: {
|
total: {
|
||||||
text: '总量',
|
text: '总量',
|
||||||
upload: '上传',
|
upload: '上传',
|
||||||
download: '下载'
|
download: '下载',
|
||||||
},
|
},
|
||||||
closeAll: {
|
closeAll: {
|
||||||
title: '警告',
|
title: '警告',
|
||||||
content: '将会关闭所有连接'
|
content: '将会关闭所有连接',
|
||||||
},
|
},
|
||||||
filter: {
|
filter: {
|
||||||
all: '全部'
|
all: '全部',
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
host: '域名',
|
host: '域名',
|
||||||
@ -73,8 +73,8 @@ const CN = {
|
|||||||
speed: '速率',
|
speed: '速率',
|
||||||
upload: '上传',
|
upload: '上传',
|
||||||
download: '下载',
|
download: '下载',
|
||||||
sourceIP: '来源 IP'
|
sourceIP: '来源 IP',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
Proxies: {
|
Proxies: {
|
||||||
title: '代理',
|
title: '代理',
|
||||||
@ -91,7 +91,7 @@ const CN = {
|
|||||||
'obfs-host': 'Obfs-host',
|
'obfs-host': 'Obfs-host',
|
||||||
uuid: 'UUID',
|
uuid: 'UUID',
|
||||||
alterId: 'AlterId',
|
alterId: 'AlterId',
|
||||||
tls: 'TLS'
|
tls: 'TLS',
|
||||||
},
|
},
|
||||||
groupTitle: '策略组',
|
groupTitle: '策略组',
|
||||||
providerTitle: '代理集',
|
providerTitle: '代理集',
|
||||||
@ -99,12 +99,12 @@ const CN = {
|
|||||||
expandText: '展开',
|
expandText: '展开',
|
||||||
collapseText: '收起',
|
collapseText: '收起',
|
||||||
speedTestText: '测速',
|
speedTestText: '测速',
|
||||||
breakConnectionsText: '切换时打断包含策略组的连接'
|
breakConnectionsText: '切换时打断包含策略组的连接',
|
||||||
},
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
ok: '确 定',
|
ok: '确 定',
|
||||||
cancel: '取 消'
|
cancel: '取 消',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CN
|
export default CN
|
||||||
|
@ -2,11 +2,11 @@ export function createAsyncSingleton<T> (fn: () => Promise<T>): () => Promise<T>
|
|||||||
let promise: Promise<T> | null = null
|
let promise: Promise<T> | null = null
|
||||||
|
|
||||||
return async function () {
|
return async function () {
|
||||||
if (promise) {
|
if (promise != null) {
|
||||||
return promise
|
return await promise
|
||||||
}
|
}
|
||||||
promise = fn()
|
promise = fn()
|
||||||
return promise
|
return await promise
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
promise = null
|
promise = null
|
||||||
throw e
|
throw e
|
||||||
|
@ -53,7 +53,7 @@ export function useInterval (callback: () => void, delay: number) {
|
|||||||
return () => clearInterval(id)
|
return () => clearInterval(id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[delay]
|
[delay],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export class JsBridge {
|
|||||||
instance: JsBridgeAPI | null = null
|
instance: JsBridgeAPI | null = null
|
||||||
|
|
||||||
constructor (callback: () => void) {
|
constructor (callback: () => void) {
|
||||||
if (window.WebViewJavascriptBridge) {
|
if (window.WebViewJavascriptBridge != null) {
|
||||||
this.instance = window.WebViewJavascriptBridge
|
this.instance = window.WebViewJavascriptBridge
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,12 +97,12 @@ export class JsBridge {
|
|||||||
return callback?.(null)
|
return callback?.(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.WebViewJavascriptBridge) {
|
if (window.WebViewJavascriptBridge != null) {
|
||||||
return callback(window.WebViewJavascriptBridge)
|
return callback(window.WebViewJavascriptBridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup callback
|
// setup callback
|
||||||
if (window.WVJBCallbacks) {
|
if (window.WVJBCallbacks != null) {
|
||||||
return window.WVJBCallbacks.push(callback)
|
return window.WVJBCallbacks.push(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,63 +115,63 @@ export class JsBridge {
|
|||||||
setTimeout(() => document.documentElement.removeChild(WVJBIframe), 0)
|
setTimeout(() => document.documentElement.removeChild(WVJBIframe), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public callHandler<T> (handleName: string, data?: any) {
|
public async callHandler<T> (handleName: string, data?: any) {
|
||||||
return new Promise<T>((resolve) => {
|
return await new Promise<T>((resolve) => {
|
||||||
this.instance?.callHandler(
|
this.instance?.callHandler(
|
||||||
handleName,
|
handleName,
|
||||||
data,
|
data,
|
||||||
resolve
|
resolve,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public ping () {
|
public async ping () {
|
||||||
return this.callHandler('ping')
|
return await this.callHandler('ping')
|
||||||
}
|
}
|
||||||
|
|
||||||
public readConfigString () {
|
public async readConfigString () {
|
||||||
return this.callHandler<string>('readConfigString')
|
return await this.callHandler<string>('readConfigString')
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPasteboard () {
|
public async getPasteboard () {
|
||||||
return this.callHandler<string>('getPasteboard')
|
return await this.callHandler<string>('getPasteboard')
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAPIInfo () {
|
public async getAPIInfo () {
|
||||||
return this.callHandler<{ host: string, port: string, secret: string }>('apiInfo')
|
return await this.callHandler<{ host: string, port: string, secret: string }>('apiInfo')
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPasteboard (data: string) {
|
public async setPasteboard (data: string) {
|
||||||
return this.callHandler('setPasteboard', data)
|
return await this.callHandler('setPasteboard', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
public writeConfigWithString (data: string) {
|
public async writeConfigWithString (data: string) {
|
||||||
return this.callHandler('writeConfigWithString', data)
|
return await this.callHandler('writeConfigWithString', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSystemProxy (data: boolean) {
|
public async setSystemProxy (data: boolean) {
|
||||||
return this.callHandler('setSystemProxy', data)
|
return await this.callHandler('setSystemProxy', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
public getStartAtLogin () {
|
public async getStartAtLogin () {
|
||||||
return this.callHandler<boolean>('getStartAtLogin')
|
return await this.callHandler<boolean>('getStartAtLogin')
|
||||||
}
|
}
|
||||||
|
|
||||||
public getProxyDelay (name: string) {
|
public async getProxyDelay (name: string) {
|
||||||
return this.callHandler<number>('speedTest', name)
|
return await this.callHandler<number>('speedTest', name)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setStartAtLogin (data: boolean) {
|
public async setStartAtLogin (data: boolean) {
|
||||||
return this.callHandler<boolean>('setStartAtLogin', data)
|
return await this.callHandler<boolean>('setStartAtLogin', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
public isSystemProxySet () {
|
public async isSystemProxySet () {
|
||||||
return this.callHandler<boolean>('isSystemProxySet')
|
return await this.callHandler<boolean>('isSystemProxySet')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupJsBridge (callback: () => void) {
|
export function setupJsBridge (callback: () => void) {
|
||||||
if (jsBridge) {
|
if (jsBridge != null) {
|
||||||
callback()
|
callback()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -94,32 +94,32 @@ export interface Connections {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Client {
|
export class Client {
|
||||||
private axiosClient: AxiosInstance
|
private readonly axiosClient: AxiosInstance
|
||||||
constructor(url: string, secret?: string) {
|
constructor (url: string, secret?: string) {
|
||||||
this.axiosClient = axios.create({
|
this.axiosClient = axios.create({
|
||||||
baseURL: url,
|
baseURL: url,
|
||||||
headers: secret ? { Authorization: `Bearer ${secret}` } : {}
|
headers: secret ? { Authorization: `Bearer ${secret}` } : {},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfig() {
|
async getConfig () {
|
||||||
return this.axiosClient.get<Config>('configs')
|
return await this.axiosClient.get<Config>('configs')
|
||||||
}
|
}
|
||||||
|
|
||||||
updateConfig(config: Partial<Config>) {
|
async updateConfig (config: Partial<Config>) {
|
||||||
return this.axiosClient.patch<void>('configs', config)
|
return await this.axiosClient.patch<void>('configs', config)
|
||||||
}
|
}
|
||||||
|
|
||||||
getRules() {
|
async getRules () {
|
||||||
return this.axiosClient.get<Rules>('rules')
|
return await this.axiosClient.get<Rules>('rules')
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProxyProviders () {
|
async getProxyProviders () {
|
||||||
const resp = await this.axiosClient.get<ProxyProviders>('providers/proxies', {
|
const resp = await this.axiosClient.get<ProxyProviders>('providers/proxies', {
|
||||||
validateStatus(status) {
|
validateStatus (status) {
|
||||||
// compatible old version
|
// compatible old version
|
||||||
return (status >= 200 && status < 300) || status === 404
|
return (status >= 200 && status < 300) || status === 404
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
if (resp.status === 404) {
|
if (resp.status === 404) {
|
||||||
resp.data = { providers: {} }
|
resp.data = { providers: {} }
|
||||||
@ -127,56 +127,56 @@ export class Client {
|
|||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
getRuleProviders () {
|
async getRuleProviders () {
|
||||||
return this.axiosClient.get<RuleProviders>('providers/rules')
|
return await this.axiosClient.get<RuleProviders>('providers/rules')
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProvider (name: string) {
|
async updateProvider (name: string) {
|
||||||
return this.axiosClient.put<void>(`providers/proxies/${encodeURIComponent(name)}`)
|
return await this.axiosClient.put<void>(`providers/proxies/${encodeURIComponent(name)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRuleProvider (name: string) {
|
async updateRuleProvider (name: string) {
|
||||||
return this.axiosClient.put<void>(`providers/rules/${encodeURIComponent(name)}`)
|
return await this.axiosClient.put<void>(`providers/rules/${encodeURIComponent(name)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
healthCheckProvider (name: string) {
|
async healthCheckProvider (name: string) {
|
||||||
return this.axiosClient.get<void>(`providers/proxies/${encodeURIComponent(name)}/healthcheck`)
|
return await this.axiosClient.get<void>(`providers/proxies/${encodeURIComponent(name)}/healthcheck`)
|
||||||
}
|
}
|
||||||
|
|
||||||
getProxies () {
|
async getProxies () {
|
||||||
return this.axiosClient.get<Proxies>('proxies')
|
return await this.axiosClient.get<Proxies>('proxies')
|
||||||
}
|
}
|
||||||
|
|
||||||
getProxy (name: string) {
|
async getProxy (name: string) {
|
||||||
return this.axiosClient.get<Proxy>(`proxies/${encodeURIComponent(name)}`)
|
return await this.axiosClient.get<Proxy>(`proxies/${encodeURIComponent(name)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVersion () {
|
async getVersion () {
|
||||||
return this.axiosClient.get<{ version: string, premium?: boolean }>('version')
|
return await this.axiosClient.get<{ version: string, premium?: boolean }>('version')
|
||||||
}
|
}
|
||||||
|
|
||||||
getProxyDelay (name: string) {
|
async getProxyDelay (name: string) {
|
||||||
return this.axiosClient.get<{ delay: number }>(`proxies/${encodeURIComponent(name)}/delay`, {
|
return await this.axiosClient.get<{ delay: number }>(`proxies/${encodeURIComponent(name)}/delay`, {
|
||||||
params: {
|
params: {
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
url: 'http://www.gstatic.com/generate_204'
|
url: 'http://www.gstatic.com/generate_204',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
closeAllConnections () {
|
async closeAllConnections () {
|
||||||
return this.axiosClient.delete('connections')
|
return await this.axiosClient.delete('connections')
|
||||||
}
|
}
|
||||||
|
|
||||||
closeConnection (id: string) {
|
async closeConnection (id: string) {
|
||||||
return this.axiosClient.delete(`connections/${id}`)
|
return await this.axiosClient.delete(`connections/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
getConnections () {
|
async getConnections () {
|
||||||
return this.axiosClient.get<Snapshot>('connections')
|
return await this.axiosClient.get<Snapshot>('connections')
|
||||||
}
|
}
|
||||||
|
|
||||||
changeProxySelected (name: string, select: string) {
|
async changeProxySelected (name: string, select: string) {
|
||||||
return this.axiosClient.put<void>(`proxies/${encodeURIComponent(name)}`, { name: select })
|
return await this.axiosClient.put<void>(`proxies/${encodeURIComponent(name)}`, { name: select })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ export class StreamReader<T> {
|
|||||||
{
|
{
|
||||||
bufferLength: 0,
|
bufferLength: 0,
|
||||||
retryInterval: 5000,
|
retryInterval: 5000,
|
||||||
headers: {}
|
headers: {},
|
||||||
},
|
},
|
||||||
config
|
config,
|
||||||
)
|
)
|
||||||
|
|
||||||
this.config.useWebsocket
|
this.config.useWebsocket
|
||||||
@ -60,13 +60,13 @@ export class StreamReader<T> {
|
|||||||
this.config.url,
|
this.config.url,
|
||||||
{
|
{
|
||||||
mode: 'cors',
|
mode: 'cors',
|
||||||
headers: this.config.token ? { Authorization: `Bearer ${this.config.token}` } : {}
|
headers: this.config.token ? { Authorization: `Bearer ${this.config.token}` } : {},
|
||||||
}
|
},
|
||||||
), e => e as Error)
|
), e => e as Error)
|
||||||
if (result.isErr()) {
|
if (result.isErr()) {
|
||||||
this.retry(result.error)
|
this.retry(result.error)
|
||||||
return
|
return
|
||||||
} else if (!result.value.body) {
|
} else if (result.value.body == null) {
|
||||||
this.retry(new Error('fetch body error'))
|
this.retry(new Error('fetch body error'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -87,7 +87,7 @@ export class StreamReader<T> {
|
|||||||
const lines = decoder.decode(result.value.value).trim().split('\n')
|
const lines = decoder.decode(result.value.value).trim().split('\n')
|
||||||
const data = lines.map(l => JSON.parse(l))
|
const data = lines.map(l => JSON.parse(l))
|
||||||
this.EE.emit('data', data)
|
this.EE.emit('data', data)
|
||||||
if (this.config.bufferLength! > 0) {
|
if (this.config.bufferLength > 0) {
|
||||||
this.innerBuffer.push(...data)
|
this.innerBuffer.push(...data)
|
||||||
if (this.innerBuffer.length > this.config.bufferLength) {
|
if (this.innerBuffer.length > this.config.bufferLength) {
|
||||||
this.innerBuffer.splice(0, this.innerBuffer.length - this.config.bufferLength)
|
this.innerBuffer.splice(0, this.innerBuffer.length - this.config.bufferLength)
|
||||||
@ -99,7 +99,7 @@ export class StreamReader<T> {
|
|||||||
protected retry (err: Error) {
|
protected retry (err: Error) {
|
||||||
if (!this.isClose) {
|
if (!this.isClose) {
|
||||||
this.EE.emit('error', err)
|
this.EE.emit('error', err)
|
||||||
window.setTimeout(this.loop, this.config.retryInterval)
|
window.setTimeout(() => { this.loop() }, this.config.retryInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export const SsCipher = [
|
|||||||
'AES-256-CFB',
|
'AES-256-CFB',
|
||||||
'CHACHA20',
|
'CHACHA20',
|
||||||
'CHACHA20-IETF',
|
'CHACHA20-IETF',
|
||||||
'XCHACHA20'
|
'XCHACHA20',
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,7 +31,7 @@ export const VmessCipher = [
|
|||||||
'auto',
|
'auto',
|
||||||
'none',
|
'none',
|
||||||
'aes-128-gcm',
|
'aes-128-gcm',
|
||||||
'chacha20-poly1305'
|
'chacha20-poly1305',
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,17 +41,17 @@ export function pickCipherWithAlias (c: string) {
|
|||||||
const cipher = c.toUpperCase()
|
const cipher = c.toUpperCase()
|
||||||
|
|
||||||
switch (cipher) {
|
switch (cipher) {
|
||||||
case 'CHACHA20-IETF-POLY1305':
|
case 'CHACHA20-IETF-POLY1305':
|
||||||
return 'AEAD_CHACHA20_POLY1305'
|
return 'AEAD_CHACHA20_POLY1305'
|
||||||
case 'XCHACHA20-IETF-POLY1305':
|
case 'XCHACHA20-IETF-POLY1305':
|
||||||
return 'AEAD_XCHACHA20_POLY1305'
|
return 'AEAD_XCHACHA20_POLY1305'
|
||||||
case 'AES-128-GCM':
|
case 'AES-128-GCM':
|
||||||
return 'AEAD_AES_128_GCM'
|
return 'AEAD_AES_128_GCM'
|
||||||
case 'AES-196-GCM':
|
case 'AES-196-GCM':
|
||||||
return 'AEAD_AES_196_GCM'
|
return 'AEAD_AES_196_GCM'
|
||||||
case 'AES-256-GCM':
|
case 'AES-256-GCM':
|
||||||
return 'AEAD_AES_256_GCM'
|
return 'AEAD_AES_256_GCM'
|
||||||
}
|
}
|
||||||
|
|
||||||
return SsCipher.find(c => c === cipher) || ''
|
return SsCipher.find(c => c === cipher) ?? ''
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
export const ProxyType = {
|
export const ProxyType = {
|
||||||
Shadowsocks: 'ss',
|
Shadowsocks: 'ss',
|
||||||
Vmess: 'vmess',
|
Vmess: 'vmess',
|
||||||
Socks5: 'socks5'
|
Socks5: 'socks5',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Proxy = ShadowsocksProxy & VmessProxy & Socks5Proxy
|
export type Proxy = ShadowsocksProxy & VmessProxy & Socks5Proxy
|
||||||
|
|
||||||
export const SsProxyConfigList = [
|
export const SsProxyConfigList = [
|
||||||
'name', 'type', 'server', 'port', 'cipher', 'password', 'obfs', 'obfs-host'
|
'name', 'type', 'server', 'port', 'cipher', 'password', 'obfs', 'obfs-host',
|
||||||
]
|
]
|
||||||
export interface ShadowsocksProxy {
|
export interface ShadowsocksProxy {
|
||||||
name?: string
|
name?: string
|
||||||
@ -32,7 +32,7 @@ export interface ShadowsocksProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const VmessProxyConfigList = [
|
export const VmessProxyConfigList = [
|
||||||
'name', 'type', 'server', 'port', 'uuid', 'alterid', 'cipher', 'tls'
|
'name', 'type', 'server', 'port', 'uuid', 'alterid', 'cipher', 'tls',
|
||||||
]
|
]
|
||||||
export interface VmessProxy {
|
export interface VmessProxy {
|
||||||
name?: string
|
name?: string
|
||||||
|
@ -34,7 +34,7 @@ export function useI18n () {
|
|||||||
}
|
}
|
||||||
return { t }
|
return { t }
|
||||||
},
|
},
|
||||||
[lang]
|
[lang],
|
||||||
)
|
)
|
||||||
|
|
||||||
return { lang, locales, setLang, translation }
|
return { lang, locales, setLang, translation }
|
||||||
@ -42,7 +42,7 @@ export function useI18n () {
|
|||||||
|
|
||||||
export const version = atom({
|
export const version = atom({
|
||||||
version: '',
|
version: '',
|
||||||
premium: false
|
premium: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useVersion () {
|
export function useVersion () {
|
||||||
@ -57,7 +57,7 @@ export function useVersion () {
|
|||||||
set(
|
set(
|
||||||
result.isErr()
|
result.isErr()
|
||||||
? { version: '', premium: false }
|
? { version: '', premium: false }
|
||||||
: { version: result.value.data.version, premium: !!result.value.data.premium }
|
: { version: result.value.data.version, premium: !!result.value.data.premium },
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ export function useRuleProviders () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const configAtom = atomWithStorage('profile', {
|
export const configAtom = atomWithStorage('profile', {
|
||||||
breakConnections: false
|
breakConnections: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useConfig () {
|
export function useConfig () {
|
||||||
@ -128,7 +128,7 @@ export function useGeneral () {
|
|||||||
redirPort: data['redir-port'],
|
redirPort: data['redir-port'],
|
||||||
mode: data.mode.toLowerCase() as Models.Data['general']['mode'],
|
mode: data.mode.toLowerCase() as Models.Data['general']['mode'],
|
||||||
logLevel: data['log-level'],
|
logLevel: data['log-level'],
|
||||||
allowLan: data['allow-lan']
|
allowLan: data['allow-lan'],
|
||||||
} as Models.Data['general']
|
} as Models.Data['general']
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -143,8 +143,8 @@ export const proxies = atomWithImmer({
|
|||||||
type: 'Selector',
|
type: 'Selector',
|
||||||
now: '',
|
now: '',
|
||||||
history: [],
|
history: [],
|
||||||
all: []
|
all: [],
|
||||||
} as API.Group
|
} as API.Group,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useProxy () {
|
export function useProxy () {
|
||||||
@ -187,7 +187,7 @@ export function useProxy () {
|
|||||||
global: allProxy.global,
|
global: allProxy.global,
|
||||||
update: mutate,
|
update: mutate,
|
||||||
markProxySelected,
|
markProxySelected,
|
||||||
set
|
set,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ export const proxyMapping = atom((get) => {
|
|||||||
const providers = get(proxyProvider)
|
const providers = get(proxyProvider)
|
||||||
const proxyMap = new Map<string, API.Proxy>()
|
const proxyMap = new Map<string, API.Proxy>()
|
||||||
for (const p of ps.proxies) {
|
for (const p of ps.proxies) {
|
||||||
proxyMap.set(p.name, p as API.Proxy)
|
proxyMap.set(p.name, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const provider of providers) {
|
for (const provider of providers) {
|
||||||
@ -214,7 +214,7 @@ export function useClashXData () {
|
|||||||
return {
|
return {
|
||||||
isClashX: false,
|
isClashX: false,
|
||||||
startAtLogin: false,
|
startAtLogin: false,
|
||||||
systemProxy: false
|
systemProxy: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ export function useRule () {
|
|||||||
|
|
||||||
const logsAtom = atom({
|
const logsAtom = atom({
|
||||||
key: '',
|
key: '',
|
||||||
instance: null as StreamReader<Log> | null
|
instance: null as StreamReader<Log> | null,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useLogsStreamReader () {
|
export function useLogsStreamReader () {
|
||||||
@ -269,7 +269,7 @@ export function useLogsStreamReader () {
|
|||||||
const instance = new StreamReader<Log>({ url: logUrl, bufferLength: 200, token: apiInfo.secret, useWebsocket })
|
const instance = new StreamReader<Log>({ url: logUrl, bufferLength: 200, token: apiInfo.secret, useWebsocket })
|
||||||
setItem({ key, instance })
|
setItem({ key, instance })
|
||||||
|
|
||||||
if (oldInstance) {
|
if (oldInstance != null) {
|
||||||
oldInstance.destory()
|
oldInstance.destory()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,6 +285,6 @@ export function useConnectionStreamReader () {
|
|||||||
const url = `${apiInfo.protocol}//${apiInfo.hostname}:${apiInfo.port}/connections`
|
const url = `${apiInfo.protocol}//${apiInfo.hostname}:${apiInfo.port}/connections`
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => version.version ? new StreamReader<Snapshot>({ url, bufferLength: 200, token: apiInfo.secret, useWebsocket }) : null,
|
() => version.version ? new StreamReader<Snapshot>({ url, bufferLength: 200, token: apiInfo.secret, useWebsocket }) : null,
|
||||||
[apiInfo.secret, url, useWebsocket, version.version]
|
[apiInfo.secret, url, useWebsocket, version.version],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { atom, useAtom } from "jotai";
|
import { atom, useAtom } from 'jotai'
|
||||||
import { isClashX, jsBridge } from "@lib/jsBridge";
|
import { isClashX, jsBridge } from '@lib/jsBridge'
|
||||||
import { atomWithStorage, useAtomValue } from "jotai/utils";
|
import { atomWithStorage, useAtomValue } from 'jotai/utils'
|
||||||
import { useLocation } from "react-use";
|
import { useLocation } from 'react-use'
|
||||||
import { Client } from "@lib/request";
|
import { Client } from '@lib/request'
|
||||||
|
|
||||||
const clashxConfigAtom = atom(async () => {
|
const clashxConfigAtom = atom(async () => {
|
||||||
if (!isClashX()) {
|
if (!isClashX()) {
|
||||||
@ -14,29 +14,29 @@ const clashxConfigAtom = atom(async () => {
|
|||||||
hostname: info.host,
|
hostname: info.host,
|
||||||
port: info.port,
|
port: info.port,
|
||||||
secret: info.secret,
|
secret: info.secret,
|
||||||
protocol: 'http:'
|
protocol: 'http:',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const localStorageAtom = atomWithStorage<{
|
export const localStorageAtom = atomWithStorage<Array<{
|
||||||
hostname: string;
|
hostname: string
|
||||||
port: string;
|
port: string
|
||||||
secret: string;
|
secret: string
|
||||||
}[]>('externalControllers', [])
|
}>>('externalControllers', [])
|
||||||
|
|
||||||
export function useAPIInfo() {
|
export function useAPIInfo () {
|
||||||
const clashx = useAtomValue(clashxConfigAtom)
|
const clashx = useAtomValue(clashxConfigAtom)
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const localStorage = useAtomValue(localStorageAtom)
|
const localStorage = useAtomValue(localStorageAtom)
|
||||||
|
|
||||||
if (clashx) {
|
if (clashx != null) {
|
||||||
return clashx
|
return clashx
|
||||||
}
|
}
|
||||||
|
|
||||||
let url: URL | undefined;
|
let url: URL | undefined
|
||||||
{
|
{
|
||||||
const meta = document.querySelector<HTMLMetaElement>('meta[name="external-controller"]')
|
const meta = document.querySelector<HTMLMetaElement>('meta[name="external-controller"]')
|
||||||
if (meta?.content?.match(/^https?:/)) {
|
if ((meta?.content?.match(/^https?:/)) != null) {
|
||||||
// [protocol]://[secret]@[hostname]:[port]
|
// [protocol]://[secret]@[hostname]:[port]
|
||||||
url = new URL(meta.content)
|
url = new URL(meta.content)
|
||||||
}
|
}
|
||||||
@ -54,15 +54,15 @@ export function useAPIInfo() {
|
|||||||
|
|
||||||
const clientAtom = atom({
|
const clientAtom = atom({
|
||||||
key: '',
|
key: '',
|
||||||
instance: null as Client | null
|
instance: null as Client | null,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useClient() {
|
export function useClient () {
|
||||||
const {
|
const {
|
||||||
hostname,
|
hostname,
|
||||||
port,
|
port,
|
||||||
secret,
|
secret,
|
||||||
protocol
|
protocol,
|
||||||
} = useAPIInfo()
|
} = useAPIInfo()
|
||||||
|
|
||||||
const [item, setItem] = useAtom(clientAtom)
|
const [item, setItem] = useAtom(clientAtom)
|
||||||
|
95
yarn.lock
95
yarn.lock
@ -422,6 +422,16 @@
|
|||||||
eslint-scope "^5.1.1"
|
eslint-scope "^5.1.1"
|
||||||
eslint-utils "^3.0.0"
|
eslint-utils "^3.0.0"
|
||||||
|
|
||||||
|
"@typescript-eslint/parser@^4.0.0":
|
||||||
|
version "4.28.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.1.tgz#5181b81658414f47291452c15bf6cd44a32f85bd"
|
||||||
|
integrity sha512-UjrMsgnhQIIK82hXGaD+MCN8IfORS1CbMdu7VlZbYa8LCZtbZjJA26De4IPQB7XYZbL8gJ99KWNj0l6WD0guJg==
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/scope-manager" "4.28.1"
|
||||||
|
"@typescript-eslint/types" "4.28.1"
|
||||||
|
"@typescript-eslint/typescript-estree" "4.28.1"
|
||||||
|
debug "^4.3.1"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^4.28.0":
|
"@typescript-eslint/parser@^4.28.0":
|
||||||
version "4.28.0"
|
version "4.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.0.tgz#2404c16751a28616ef3abab77c8e51d680a12caa"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.0.tgz#2404c16751a28616ef3abab77c8e51d680a12caa"
|
||||||
@ -440,11 +450,24 @@
|
|||||||
"@typescript-eslint/types" "4.28.0"
|
"@typescript-eslint/types" "4.28.0"
|
||||||
"@typescript-eslint/visitor-keys" "4.28.0"
|
"@typescript-eslint/visitor-keys" "4.28.0"
|
||||||
|
|
||||||
|
"@typescript-eslint/scope-manager@4.28.1":
|
||||||
|
version "4.28.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.1.tgz#fd3c20627cdc12933f6d98b386940d8d0ce8a991"
|
||||||
|
integrity sha512-o95bvGKfss6705x7jFGDyS7trAORTy57lwJ+VsYwil/lOUxKQ9tA7Suuq+ciMhJc/1qPwB3XE2DKh9wubW8YYA==
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/types" "4.28.1"
|
||||||
|
"@typescript-eslint/visitor-keys" "4.28.1"
|
||||||
|
|
||||||
"@typescript-eslint/types@4.28.0":
|
"@typescript-eslint/types@4.28.0":
|
||||||
version "4.28.0"
|
version "4.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.0.tgz#a33504e1ce7ac51fc39035f5fe6f15079d4dafb0"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.0.tgz#a33504e1ce7ac51fc39035f5fe6f15079d4dafb0"
|
||||||
integrity sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==
|
integrity sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==
|
||||||
|
|
||||||
|
"@typescript-eslint/types@4.28.1":
|
||||||
|
version "4.28.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.1.tgz#d0f2ecbef3684634db357b9bbfc97b94b828f83f"
|
||||||
|
integrity sha512-4z+knEihcyX7blAGi7O3Fm3O6YRCP+r56NJFMNGsmtdw+NCdpG5SgNz427LS9nQkRVTswZLhz484hakQwB8RRg==
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@4.28.0":
|
"@typescript-eslint/typescript-estree@4.28.0":
|
||||||
version "4.28.0"
|
version "4.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz#e66d4e5aa2ede66fec8af434898fe61af10c71cf"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz#e66d4e5aa2ede66fec8af434898fe61af10c71cf"
|
||||||
@ -458,6 +481,19 @@
|
|||||||
semver "^7.3.5"
|
semver "^7.3.5"
|
||||||
tsutils "^3.21.0"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
|
"@typescript-eslint/typescript-estree@4.28.1":
|
||||||
|
version "4.28.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.1.tgz#af882ae41740d1f268e38b4d0fad21e7e8d86a81"
|
||||||
|
integrity sha512-GhKxmC4sHXxHGJv8e8egAZeTZ6HI4mLU6S7FUzvFOtsk7ZIDN1ksA9r9DyOgNqowA9yAtZXV0Uiap61bIO81FQ==
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/types" "4.28.1"
|
||||||
|
"@typescript-eslint/visitor-keys" "4.28.1"
|
||||||
|
debug "^4.3.1"
|
||||||
|
globby "^11.0.3"
|
||||||
|
is-glob "^4.0.1"
|
||||||
|
semver "^7.3.5"
|
||||||
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@4.28.0":
|
"@typescript-eslint/visitor-keys@4.28.0":
|
||||||
version "4.28.0"
|
version "4.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz#255c67c966ec294104169a6939d96f91c8a89434"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz#255c67c966ec294104169a6939d96f91c8a89434"
|
||||||
@ -466,6 +502,14 @@
|
|||||||
"@typescript-eslint/types" "4.28.0"
|
"@typescript-eslint/types" "4.28.0"
|
||||||
eslint-visitor-keys "^2.0.0"
|
eslint-visitor-keys "^2.0.0"
|
||||||
|
|
||||||
|
"@typescript-eslint/visitor-keys@4.28.1":
|
||||||
|
version "4.28.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.1.tgz#162a515ee255f18a6068edc26df793cdc1ec9157"
|
||||||
|
integrity sha512-K4HMrdFqr9PFquPu178SaSb92CaWe2yErXyPumc8cYWxFmhgJsNY9eSePmO05j0JhBvf2Cdhptd6E6Yv9HVHcg==
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/types" "4.28.1"
|
||||||
|
eslint-visitor-keys "^2.0.0"
|
||||||
|
|
||||||
"@vitejs/plugin-react-refresh@^1.3.3":
|
"@vitejs/plugin-react-refresh@^1.3.3":
|
||||||
version "1.3.3"
|
version "1.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.3.tgz#d5afb3e0463f368a8afadfdd7305fe5c5fe78a6a"
|
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.3.tgz#d5afb3e0463f368a8afadfdd7305fe5c5fe78a6a"
|
||||||
@ -1016,6 +1060,19 @@ eslint-config-react-app@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
confusing-browser-globals "^1.0.10"
|
confusing-browser-globals "^1.0.10"
|
||||||
|
|
||||||
|
eslint-config-standard-with-typescript@^20.0.0:
|
||||||
|
version "20.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-20.0.0.tgz#0c550eca0a216cbf8da9013eb6e311acd3102d87"
|
||||||
|
integrity sha512-IoySf3r0a2+P3Z6GMjv8p1HuOQ6GWQbMpdt9G8uEbkGpnNWAGBXpgaiutbZHbaQAvG5pkVtYepCfHUxYbVDLCA==
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/parser" "^4.0.0"
|
||||||
|
eslint-config-standard "^16.0.0"
|
||||||
|
|
||||||
|
eslint-config-standard@^16.0.0:
|
||||||
|
version "16.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz#6c8761e544e96c531ff92642eeb87842b8488516"
|
||||||
|
integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==
|
||||||
|
|
||||||
eslint-import-resolver-node@^0.3.4:
|
eslint-import-resolver-node@^0.3.4:
|
||||||
version "0.3.4"
|
version "0.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
|
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
|
||||||
@ -1032,6 +1089,14 @@ eslint-module-utils@^2.6.1:
|
|||||||
debug "^3.2.7"
|
debug "^3.2.7"
|
||||||
pkg-dir "^2.0.0"
|
pkg-dir "^2.0.0"
|
||||||
|
|
||||||
|
eslint-plugin-es@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
|
||||||
|
integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
|
||||||
|
dependencies:
|
||||||
|
eslint-utils "^2.0.0"
|
||||||
|
regexpp "^3.0.0"
|
||||||
|
|
||||||
eslint-plugin-flowtype@^5.7.2:
|
eslint-plugin-flowtype@^5.7.2:
|
||||||
version "5.7.2"
|
version "5.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.7.2.tgz#482a42fe5d15ee614652ed256d37543d584d7bc0"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.7.2.tgz#482a42fe5d15ee614652ed256d37543d584d7bc0"
|
||||||
@ -1078,6 +1143,23 @@ eslint-plugin-jsx-a11y@^6.4.1:
|
|||||||
jsx-ast-utils "^3.1.0"
|
jsx-ast-utils "^3.1.0"
|
||||||
language-tags "^1.0.5"
|
language-tags "^1.0.5"
|
||||||
|
|
||||||
|
eslint-plugin-node@^11.1.0:
|
||||||
|
version "11.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
|
||||||
|
integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
|
||||||
|
dependencies:
|
||||||
|
eslint-plugin-es "^3.0.0"
|
||||||
|
eslint-utils "^2.0.0"
|
||||||
|
ignore "^5.1.1"
|
||||||
|
minimatch "^3.0.4"
|
||||||
|
resolve "^1.10.1"
|
||||||
|
semver "^6.1.0"
|
||||||
|
|
||||||
|
eslint-plugin-promise@^5.1.0:
|
||||||
|
version "5.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz#fb2188fb734e4557993733b41aa1a688f46c6f24"
|
||||||
|
integrity sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==
|
||||||
|
|
||||||
eslint-plugin-react-hooks@^4.2.0:
|
eslint-plugin-react-hooks@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556"
|
||||||
@ -1109,7 +1191,7 @@ eslint-scope@^5.1.1:
|
|||||||
esrecurse "^4.3.0"
|
esrecurse "^4.3.0"
|
||||||
estraverse "^4.1.1"
|
estraverse "^4.1.1"
|
||||||
|
|
||||||
eslint-utils@^2.1.0:
|
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
|
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
|
||||||
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
|
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
|
||||||
@ -1469,7 +1551,7 @@ ignore@^4.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
|
||||||
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
|
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
|
||||||
|
|
||||||
ignore@^5.1.4:
|
ignore@^5.1.1, ignore@^5.1.4:
|
||||||
version "5.1.8"
|
version "5.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
|
||||||
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
|
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
|
||||||
@ -2258,6 +2340,11 @@ regexp.prototype.flags@^1.3.1:
|
|||||||
call-bind "^1.0.2"
|
call-bind "^1.0.2"
|
||||||
define-properties "^1.1.3"
|
define-properties "^1.1.3"
|
||||||
|
|
||||||
|
regexpp@^3.0.0:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
|
||||||
|
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
|
||||||
|
|
||||||
regexpp@^3.1.0:
|
regexpp@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
|
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
|
||||||
@ -2283,7 +2370,7 @@ resolve-pathname@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
|
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
|
||||||
integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
|
integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
|
||||||
|
|
||||||
resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.20.0:
|
resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.20.0:
|
||||||
version "1.20.0"
|
version "1.20.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||||
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||||
@ -2362,7 +2449,7 @@ screenfull@^5.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||||
|
|
||||||
semver@^6.3.0:
|
semver@^6.1.0, semver@^6.3.0:
|
||||||
version "6.3.0"
|
version "6.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user