1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
import React from 'react';
import { RotateCw, Zap } from 'react-feather';
import { formatDistance } from 'date-fns';
import { motion } from 'framer-motion';
import { connect } from './StateProvider';
import Collapsible from './Collapsible';
import CollapsibleSectionHeader from './CollapsibleSectionHeader';
import {
ProxyList,
ProxyListSummaryView,
filterAvailableProxiesAndSort
} from './ProxyGroup';
import Button from './Button';
import { getClashAPIConfig } from '../store/app';
import {
getDelay,
getRtFilterSwitch,
updateProviderByName,
healthcheckProviderByName
} from '../store/proxies';
import s from './ProxyProvider.module.css';
const { useState, useCallback } = React;
type Props = {
name: string,
proxies: Array<string>,
type: 'Proxy' | 'Rule',
vehicleType: 'HTTP' | 'File' | 'Compatible',
updatedAt?: string,
dispatch: any => void
};
function ProxyProvider({
name,
proxies,
vehicleType,
updatedAt,
dispatch,
apiConfig
}: Props) {
const [isHealthcheckLoading, setIsHealthcheckLoading] = useState(false);
const updateProvider = useCallback(
() => dispatch(updateProviderByName(apiConfig, name)),
[apiConfig, dispatch, name]
);
const healthcheckProvider = useCallback(async () => {
setIsHealthcheckLoading(true);
await dispatch(healthcheckProviderByName(apiConfig, name));
setIsHealthcheckLoading(false);
}, [apiConfig, dispatch, name, setIsHealthcheckLoading]);
const [isCollapsibleOpen, setCollapsibleOpen] = useState(false);
const toggle = useCallback(() => setCollapsibleOpen(x => !x), []);
const timeAgo = formatDistance(new Date(updatedAt), new Date());
return (
<div className={s.body}>
<CollapsibleSectionHeader
name={name}
toggle={toggle}
type={vehicleType}
isOpen={isCollapsibleOpen}
qty={proxies.length}
/>
<div className={s.updatedAt}>
<small>Updated {timeAgo} ago</small>
</div>
<Collapsible isOpen={isCollapsibleOpen}>
<ProxyList all={proxies} />
<div className={s.actionFooter}>
<Button text="Update" start={<Refresh />} onClick={updateProvider} />
<Button
text="Health Check"
start={<Zap size={16} />}
onClick={healthcheckProvider}
isLoading={isHealthcheckLoading}
/>
</div>
</Collapsible>
<Collapsible isOpen={!isCollapsibleOpen}>
<ProxyListSummaryView all={proxies} />
</Collapsible>
</div>
);
}
const button = {
rest: { scale: 1 },
// hover: { scale: 1.1 },
pressed: { scale: 0.95 }
};
const arrow = {
rest: { rotate: 0 },
hover: { rotate: 360, transition: { duration: 0.3 } }
};
function Refresh() {
return (
<motion.div
className={s.refresh}
variants={button}
initial="rest"
whileHover="hover"
whileTap="pressed"
>
<motion.div className="flexCenter" variants={arrow}>
<RotateCw size={16} />
</motion.div>
</motion.div>
);
}
const mapState = (s, { proxies }) => {
const filterByRt = getRtFilterSwitch(s);
const delay = getDelay(s);
const apiConfig = getClashAPIConfig(s);
return {
apiConfig,
proxies: filterAvailableProxiesAndSort(proxies, delay, filterByRt)
};
};
// const mapState = s => ({
// apiConfig: getClashAPIConfig(s)
// });
export default connect(mapState)(ProxyProvider);
|