Always show update and health check buttons for proxy provider

ref #649
This commit is contained in:
Haishan 2022-06-12 09:30:45 +08:00
parent e62b958e30
commit 69423bdfff
8 changed files with 102 additions and 67 deletions

View file

@ -4,6 +4,7 @@ import Loading from 'src/components/Loading';
import Button from './Button';
import Input from './Input';
import { ZapAnimated } from './shared/ZapAnimated';
import SwitchThemed from './SwitchThemed';
import ToggleSwitch from './ToggleSwitch';
@ -42,6 +43,9 @@ class StyleGuide extends PureComponent {
render() {
return (
<div>
<Pane>
<ZapAnimated />
</Pane>
<Pane>
<SwitchExample />
</Pane>

View file

@ -4,17 +4,10 @@
.groupHead {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.latencyButton {
margin-left: 5px;
}
.zapWrapper {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
.action {
margin: 0 5px;
}

View file

@ -1,26 +1,20 @@
import Tooltip from '@reach/tooltip';
import * as React from 'react';
import { Zap } from 'react-feather';
import { useState2 } from '$src/hooks/basic';
import { State } from '$src/store/types';
import { getCollapsibleIsOpen, getHideUnavailableProxies, getProxySortBy } from '../../store/app';
import { getProxies, switchProxy } from '../../store/proxies';
import Button from '../Button';
import CollapsibleSectionHeader from '../CollapsibleSectionHeader';
import { ZapAnimated } from '../shared/ZapAnimated';
import { connect, useStoreActions } from '../StateProvider';
import { useFilteredAndSorted } from './hooks';
import s0 from './ProxyGroup.module.scss';
import { ProxyList, ProxyListSummaryView } from './ProxyList';
const { createElement, useCallback, useMemo, useState } = React;
function ZapWrapper() {
return (
<div className={s0.zapWrapper}>
<Zap size={16} />
</div>
);
}
const { createElement, useCallback, useMemo } = React;
function ProxyGroupImpl({
name,
@ -56,14 +50,15 @@ function ProxyGroupImpl({
[apiConfig, dispatch, name, isSelectable]
);
const [isTestingLatency, setIsTestingLatency] = useState(false);
const testingLatency = useState2(false);
const testLatency = useCallback(async () => {
setIsTestingLatency(true);
if (testingLatency.value) return;
testingLatency.set(true);
try {
await requestDelayForProxies(apiConfig, all);
} catch (err) {}
setIsTestingLatency(false);
}, [all, apiConfig, requestDelayForProxies]);
testingLatency.set(false);
}, [all, apiConfig, requestDelayForProxies, testingLatency]);
return (
<div className={s0.group}>
@ -75,15 +70,13 @@ function ProxyGroupImpl({
qty={all.length}
isOpen={isOpen}
/>
<Button
className={s0.latencyButton}
title="Test latency"
kind="minimal"
onClick={testLatency}
isLoading={isTestingLatency}
>
<ZapWrapper />
</Button>
<div className={s0.action}>
<Tooltip label={'Test latency'}>
<Button kind="circular" onClick={testLatency}>
<ZapAnimated animate={testingLatency.value} size={16} />
</Button>
</Tooltip>
</div>
</div>
{createElement(isOpen ? ProxyList : ProxyListSummaryView, {
all,

View file

@ -6,9 +6,10 @@
}
.listSummaryView {
margin: 8px 0;
margin: 14px 0;
display: grid;
grid-template-columns: repeat(auto-fill, 13px);
grid-gap: 10px;
place-items: center;
max-width: 900px;
}

View file

@ -5,21 +5,25 @@
}
}
.body {
.main {
padding: 10px 15px;
@media (--breakpoint-not-small) {
padding: 10px 40px;
}
}
.actionFooter {
.head {
display: flex;
button {
margin: 0 5px;
&:first-child {
margin-left: 0;
}
}
align-items: center;
flex-wrap: wrap;
}
.action {
margin: 0 5px;
display: grid;
grid-template-columns: auto auto;
gap: 10px;
place-items: center;
}
.refresh {

View file

@ -1,8 +1,8 @@
import Tooltip from '@reach/tooltip';
import { formatDistance } from 'date-fns';
import * as React from 'react';
import { RotateCw, Zap } from 'react-feather';
import { RotateCw } from 'react-feather';
import Button from 'src/components/Button';
import Collapsible from 'src/components/Collapsible';
import CollapsibleSectionHeader from 'src/components/CollapsibleSectionHeader';
import { useUpdateProviderItem } from 'src/components/proxies/proxies.hooks';
import { connect, useStoreActions } from 'src/components/StateProvider';
@ -18,6 +18,7 @@ import { DelayMapping, State } from 'src/store/types';
import { useState2 } from '$src/hooks/basic';
import { ZapAnimated } from '../shared/ZapAnimated';
import { useFilteredAndSorted } from './hooks';
import { ProxyList, ProxyListSummaryView } from './ProxyList';
import s from './ProxyProvider.module.scss';
@ -56,6 +57,7 @@ function ProxyProviderImpl({
const updateProvider = useUpdateProviderItem({ dispatch, apiConfig, name });
const healthcheckProvider = useCallback(() => {
if (checkingHealth.value) return;
checkingHealth.set(true);
const stop = () => checkingHealth.set(false);
dispatch(healthcheckProviderByName(apiConfig, name)).then(stop, stop);
@ -71,32 +73,33 @@ function ProxyProviderImpl({
const timeAgo = formatDistance(new Date(updatedAt), new Date());
return (
<div className={s.body}>
<CollapsibleSectionHeader
name={name}
toggle={toggle}
type={vehicleType}
isOpen={isOpen}
qty={proxies.length}
/>
<div className={s.main}>
<div className={s.head}>
<CollapsibleSectionHeader
name={name}
toggle={toggle}
type={vehicleType}
isOpen={isOpen}
qty={proxies.length}
/>
<div className={s.action}>
<Tooltip label={'Update'}>
<Button kind="circular" onClick={updateProvider}>
<Refresh />
</Button>
</Tooltip>
<Tooltip label={'Health Check'}>
<Button kind="circular" onClick={healthcheckProvider}>
<ZapAnimated animate={checkingHealth.value} size={16} />
</Button>
</Tooltip>
</div>
</div>
<div className={s.updatedAt}>
<small>Updated {timeAgo} ago</small>
</div>
<Collapsible isOpen={isOpen}>
<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={checkingHealth.value}
/>
</div>
</Collapsible>
<Collapsible isOpen={!isOpen}>
<ProxyListSummaryView all={proxies} />
</Collapsible>
{isOpen ? <ProxyList all={proxies} /> : <ProxyListSummaryView all={proxies} />}
</div>
);
}

View file

@ -0,0 +1,12 @@
.animate {
--saturation: 70%;
stroke: hsl(46deg var(--saturation) 45%);
animation: zap-pulse 0.7s 0s ease-in-out none normal infinite;
}
// prettier-ignore
@keyframes zap-pulse {
0% { stroke: hsl(46deg var(--saturation) 45%); }
50% { stroke: hsl(46deg var(--saturation) 95%); }
100% { stroke: hsl(46deg var(--saturation) 45%); }
}

View file

@ -0,0 +1,25 @@
import cx from 'clsx';
import * as React from 'react';
import s from './ZapAnimated.module.scss';
export function ZapAnimated(props: { size?: number; animate?: boolean }) {
const size = props.size || 24;
const cls = cx({ [s.animate]: props.animate });
return (
<svg
className={cls}
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
</svg>
);
}