From 7f7cb27df139d6ca73031789539ea2ba2f2ecb77 Mon Sep 17 00:00:00 2001
From: Haishan <haishanhan@gmail.com>
Date: Mon, 6 Jun 2022 00:02:54 +0800
Subject: Make button slightly bigger than before

---
 src/components/shared/RotateIcon.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/shared/RotateIcon.tsx')

diff --git a/src/components/shared/RotateIcon.tsx b/src/components/shared/RotateIcon.tsx
index 7e3ceae..d9dcbd9 100644
--- a/src/components/shared/RotateIcon.tsx
+++ b/src/components/shared/RotateIcon.tsx
@@ -10,7 +10,7 @@ export function RotateIcon({ isRotating }: { isRotating: boolean }) {
   });
   return (
     <span className={cls}>
-      <RotateCw width={16} />
+      <RotateCw size={16} />
     </span>
   );
 }
-- 
cgit v1.3.1


From 78f3434cb52f53c66936de278f0828c19ef63666 Mon Sep 17 00:00:00 2001
From: Haishan <haishanhan@gmail.com>
Date: Mon, 6 Jun 2022 23:39:56 +0800
Subject: Run prettier

---
 src/api/configs.ts                                |  5 +-
 src/api/connections.ts                            |  5 +-
 src/api/proxies.ts                                |  5 +-
 src/api/rule-provider.ts                          |  5 +-
 src/api/rules.ts                                  |  4 +-
 src/api/traffic.ts                                |  2 +-
 src/components/APIConfig.tsx                      |  5 +-
 src/components/BackendList.tsx                    | 11 +---
 src/components/Collapsible.tsx                    | 13 +----
 src/components/CollapsibleSectionHeader.tsx       |  7 +--
 src/components/ConnectionTable.tsx                |  5 +-
 src/components/Logs.tsx                           |  2 +-
 src/components/Rules.tsx                          |  2 +-
 src/components/Search.tsx                         |  7 +--
 src/components/SideBar.tsx                        |  9 +---
 src/components/SvgYacd.tsx                        |  7 +--
 src/components/ToggleSwitch.tsx                   |  5 +-
 src/components/TrafficChart.tsx                   | 10 ++--
 src/components/about/About.tsx                    | 29 ++--------
 src/components/proxies/ClosePrevConns.tsx         |  9 ++--
 src/components/proxies/Proxies.tsx                | 20 ++-----
 src/components/proxies/Proxy.module.scss          |  3 --
 src/components/proxies/Proxy.tsx                  | 27 ++--------
 src/components/proxies/ProxyGroup.module.scss     |  9 ++++
 src/components/proxies/ProxyGroup.tsx             | 23 +++-----
 src/components/proxies/ProxyList.tsx              |  7 +--
 src/components/proxies/ProxyPageFab.tsx           |  7 +--
 src/components/proxies/ProxyProvider.tsx          |  7 +--
 src/components/proxies/ProxyProviderList.tsx      |  6 +--
 src/components/proxies/Settings.tsx               |  6 +--
 src/components/proxies/hooks.tsx                  | 12 +----
 src/components/proxies/proxies.hooks.tsx          |  9 ++--
 src/components/rules/RuleProviderItem.module.scss | 13 ++---
 src/components/rules/RuleProviderItem.tsx         | 14 ++---
 src/components/shared/Fab.tsx                     | 12 ++---
 src/components/shared/RotateIcon.tsx              |  9 ++--
 src/components/shared/TextFitler.tsx              |  5 +-
 src/components/svg/Equalizer.tsx                  |  5 +-
 src/hooks/useRemainingViewPortHeight.ts           |  7 +--
 src/hooks/useTextInput.ts                         |  4 +-
 src/misc/chart.ts                                 |  4 +-
 src/misc/i18n.ts                                  |  5 +-
 src/misc/motion.ts                                |  4 +-
 src/misc/request-helper.ts                        |  6 +--
 src/misc/shallowEqual.ts                          |  7 +--
 src/misc/utils.ts                                 | 10 +---
 src/store/app.ts                                  |  4 +-
 src/store/configs.ts                              |  8 +--
 src/store/proxies.tsx                             | 65 ++++++-----------------
 src/sw.ts                                         |  3 +-
 src/swRegistration.ts                             | 12 ++---
 src/types.ts                                      |  2 +-
 52 files changed, 127 insertions(+), 355 deletions(-)

(limited to 'src/components/shared/RotateIcon.tsx')

diff --git a/src/api/configs.ts b/src/api/configs.ts
index 69b02d4..3646f1a 100644
--- a/src/api/configs.ts
+++ b/src/api/configs.ts
@@ -22,10 +22,7 @@ function configsPatchWorkaround(o: ClashConfigPartial) {
   return o;
 }
 
-export async function updateConfigs(
-  apiConfig: ClashAPIConfig,
-  o: ClashConfigPartial
-) {
+export async function updateConfigs(apiConfig: ClashAPIConfig, o: ClashConfigPartial) {
   const { url, init } = getURLAndInit(apiConfig);
   const body = JSON.stringify(configsPatchWorkaround(o));
   return await fetch(url + endpoint, { ...init, body, method: 'PATCH' });
diff --git a/src/api/connections.ts b/src/api/connections.ts
index 9c94d31..60fd4c5 100644
--- a/src/api/connections.ts
+++ b/src/api/connections.ts
@@ -51,10 +51,7 @@ function appendData(s: string) {
 type UnsubscribeFn = () => void;
 
 let wsState: number;
-export function fetchData(
-  apiConfig: ClashAPIConfig,
-  listener: unknown
-): UnsubscribeFn | void {
+export function fetchData(apiConfig: ClashAPIConfig, listener: unknown): UnsubscribeFn | void {
   if (fetched || wsState === 1) {
     if (listener) return subscribe(listener);
   }
diff --git a/src/api/proxies.ts b/src/api/proxies.ts
index 6b3e28e..e11fd9e 100644
--- a/src/api/proxies.ts
+++ b/src/api/proxies.ts
@@ -59,8 +59,5 @@ export async function updateProviderByName(config, name) {
 export async function healthcheckProviderByName(config, name) {
   const { url, init } = getURLAndInit(config);
   const options = { ...init, method: 'GET' };
-  return await fetch(
-    url + '/providers/proxies/' + name + '/healthcheck',
-    options
-  );
+  return await fetch(url + '/providers/proxies/' + name + '/healthcheck', options);
 }
diff --git a/src/api/rule-provider.ts b/src/api/rule-provider.ts
index ec9fa7b..5ecd61e 100644
--- a/src/api/rule-provider.ts
+++ b/src/api/rule-provider.ts
@@ -31,10 +31,7 @@ function normalizeAPIResponse(data: RuleProviderAPIData) {
   return { byName, names };
 }
 
-export async function fetchRuleProviders(
-  endpoint: string,
-  apiConfig: ClashAPIConfig
-) {
+export async function fetchRuleProviders(endpoint: string, apiConfig: ClashAPIConfig) {
   const { url, init } = getURLAndInit(apiConfig);
 
   let data = { providers: {} };
diff --git a/src/api/rules.ts b/src/api/rules.ts
index b57b0e3..4d18c23 100644
--- a/src/api/rules.ts
+++ b/src/api/rules.ts
@@ -12,9 +12,7 @@ type RuleAPIItem = {
   proxy: string;
 };
 
-function normalizeAPIResponse(json: {
-  rules: Array<RuleAPIItem>;
-}): Array<RuleItem> {
+function normalizeAPIResponse(json: { rules: Array<RuleAPIItem> }): Array<RuleItem> {
   invariant(
     json.rules && json.rules.length >= 0,
     'there is no valid rules list in the rules API response'
diff --git a/src/api/traffic.ts b/src/api/traffic.ts
index cd18aac..aa9143c 100644
--- a/src/api/traffic.ts
+++ b/src/api/traffic.ts
@@ -27,7 +27,7 @@ const traffic = {
     this.subscribers.forEach((f) => f(o));
   },
 
-  subscribe(listener: (x:any) => void) {
+  subscribe(listener: (x: any) => void) {
     this.subscribers.push(listener);
     return () => {
       const idx = this.subscribers.indexOf(listener);
diff --git a/src/components/APIConfig.tsx b/src/components/APIConfig.tsx
index 6e11bc4..4a11c92 100644
--- a/src/components/APIConfig.tsx
+++ b/src/components/APIConfig.tsx
@@ -72,9 +72,9 @@ function APIConfig({ dispatch }) {
   const detectApiServer = async () => {
     // if there is already a clash API server at `/`, just use it as default value
     const res = await fetch('/');
-    res.json().then(data => {
+    res.json().then((data) => {
       if (data['hello'] === 'clash') {
-        setBaseURL(window.location.origin)
+        setBaseURL(window.location.origin);
       }
     });
   };
@@ -82,7 +82,6 @@ function APIConfig({ dispatch }) {
     detectApiServer();
   }, []);
 
-
   return (
     // eslint-disable-next-line jsx-a11y/no-static-element-interactions
     <div className={s0.root} ref={contentEl} onKeyDown={handleContentOnKeyDown}>
diff --git a/src/components/BackendList.tsx b/src/components/BackendList.tsx
index 8e0d906..e4f4d80 100644
--- a/src/components/BackendList.tsx
+++ b/src/components/BackendList.tsx
@@ -2,10 +2,7 @@ import cx from 'clsx';
 import * as React from 'react';
 import { Eye, EyeOff, X as Close } from 'react-feather';
 import { useToggle } from 'src/hooks/basic';
-import {
-  getClashAPIConfigs,
-  getSelectedClashAPIConfigIndex,
-} from 'src/store/app';
+import { getClashAPIConfigs, getSelectedClashAPIConfigIndex } from 'src/store/app';
 import { ClashAPIConfig } from 'src/types';
 
 import s from './BackendList.module.scss';
@@ -137,11 +134,7 @@ function Button({
   disabled?: boolean;
 }) {
   return (
-    <button
-      disabled={disabled}
-      className={cx(className, s.btn)}
-      onClick={onClick}
-    >
+    <button disabled={disabled} className={cx(className, s.btn)} onClick={onClick}>
       {children}
     </button>
   );
diff --git a/src/components/Collapsible.tsx b/src/components/Collapsible.tsx
index e9a1ee8..819bc7c 100644
--- a/src/components/Collapsible.tsx
+++ b/src/components/Collapsible.tsx
@@ -60,20 +60,11 @@ const Collapsible = memo(({ children, isOpen }) => {
   return (
     <div>
       <motion.div
-        animate={
-          isOpen && previous === isOpen
-            ? 'initialOpen'
-            : isOpen
-            ? 'open'
-            : 'closed'
-        }
+        animate={isOpen && previous === isOpen ? 'initialOpen' : isOpen ? 'open' : 'closed'}
         custom={height}
         variants={variantsCollpapsibleWrap}
       >
-        <motion.div
-          variants={variantsCollpapsibleChildContainer}
-          ref={refToMeature}
-        >
+        <motion.div variants={variantsCollpapsibleChildContainer} ref={refToMeature}>
           {children}
         </motion.div>
       </motion.div>
diff --git a/src/components/CollapsibleSectionHeader.tsx b/src/components/CollapsibleSectionHeader.tsx
index 2d5ecd1..8b701e1 100644
--- a/src/components/CollapsibleSectionHeader.tsx
+++ b/src/components/CollapsibleSectionHeader.tsx
@@ -39,12 +39,7 @@ export default function Header({ name, type, toggle, isOpen, qty }: Props) {
 
       {typeof qty === 'number' ? <span className={s.qty}>{qty}</span> : null}
 
-      <Button
-        kind="minimal"
-        onClick={toggle}
-        className={s.btn}
-        title="Toggle collapsible section"
-      >
+      <Button kind="minimal" onClick={toggle} className={s.btn} title="Toggle collapsible section">
         <span className={cx(s.arrow, { [s.isOpen]: isOpen })}>
           <ChevronDown size={20} />
         </span>
diff --git a/src/components/ConnectionTable.tsx b/src/components/ConnectionTable.tsx
index 2323e2e..15261a3 100644
--- a/src/components/ConnectionTable.tsx
+++ b/src/components/ConnectionTable.tsx
@@ -64,10 +64,7 @@ function Table({ data }) {
         return (
           <div {...headerGroup.getHeaderGroupProps()} className={s.tr}>
             {headerGroup.headers.map((column) => (
-              <div
-                {...column.getHeaderProps(column.getSortByToggleProps())}
-                className={s.th}
-              >
+              <div {...column.getHeaderProps(column.getSortByToggleProps())} className={s.th}>
                 <span>{column.render('Header')}</span>
                 <span className={s.sortIconContainer}>
                   {column.isSorted ? (
diff --git a/src/components/Logs.tsx b/src/components/Logs.tsx
index d9c53d7..5930634 100644
--- a/src/components/Logs.tsx
+++ b/src/components/Logs.tsx
@@ -3,7 +3,7 @@ import * as React from 'react';
 import { Pause, Play } from 'react-feather';
 import { useTranslation } from 'react-i18next';
 import { areEqual, FixedSizeList as List, ListChildComponentProps } from 'react-window';
-import { fetchLogs, reconnect as reconnectLogs,stop as stopLogs } from 'src/api/logs';
+import { fetchLogs, reconnect as reconnectLogs, stop as stopLogs } from 'src/api/logs';
 import ContentHeader from 'src/components/ContentHeader';
 import LogSearch from 'src/components/LogSearch';
 import { connect, useStoreActions } from 'src/components/StateProvider';
diff --git a/src/components/Rules.tsx b/src/components/Rules.tsx
index 47644e7..e6e1422 100644
--- a/src/components/Rules.tsx
+++ b/src/components/Rules.tsx
@@ -41,7 +41,7 @@ function getItemSizeFactory({ provider }) {
     const providerQty = provider.names.length;
     if (idx < providerQty) {
       // provider
-      return 90;
+      return 110;
     }
     // rule
     return 80;
diff --git a/src/components/Search.tsx b/src/components/Search.tsx
index 6edc4a5..9762d8f 100644
--- a/src/components/Search.tsx
+++ b/src/components/Search.tsx
@@ -25,12 +25,7 @@ function RuleSearch({ dispatch, searchText, updateSearchText }) {
     <div className={s0.RuleSearch}>
       <div className={s0.RuleSearchContainer}>
         <div className={s0.inputWrapper}>
-          <input
-            type="text"
-            value={text}
-            onChange={onChange}
-            className={s0.input}
-          />
+          <input type="text" value={text} onChange={onChange} className={s0.input} />
         </div>
         <div className={s0.iconWrapper}>
           <SearchIcon size={20} />
diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx
index dbe7f0d..2c5ba0c 100644
--- a/src/components/SideBar.tsx
+++ b/src/components/SideBar.tsx
@@ -3,14 +3,7 @@ import cx from 'clsx';
 import * as React from 'react';
 import { Info } from 'react-feather';
 import { useTranslation } from 'react-i18next';
-import {
-  FcAreaChart,
-  FcDocument,
-  FcGlobe,
-  FcLink,
-  FcRuler,
-  FcSettings,
-} from 'react-icons/fc';
+import { FcAreaChart, FcDocument, FcGlobe, FcLink, FcRuler, FcSettings } from 'react-icons/fc';
 import { Link, useLocation } from 'react-router-dom';
 import { ThemeSwitcher } from 'src/components/shared/ThemeSwitcher';
 
diff --git a/src/components/SvgYacd.tsx b/src/components/SvgYacd.tsx
index 63c0bd5..499456d 100644
--- a/src/components/SvgYacd.tsx
+++ b/src/components/SvgYacd.tsx
@@ -25,12 +25,7 @@ function SvgYacd({
 }: Props) {
   const faceClasName = cx({ [s.path]: animate });
   return (
-    <svg
-      width={width}
-      height={height}
-      viewBox="0 0 320 320"
-      xmlns="http://www.w3.org/2000/svg"
-    >
+    <svg width={width} height={height} viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg">
       <g fill="none" fillRule="evenodd">
         {/* face */}
         <path
diff --git a/src/components/ToggleSwitch.tsx b/src/components/ToggleSwitch.tsx
index 9eb1019..58400c9 100644
--- a/src/components/ToggleSwitch.tsx
+++ b/src/components/ToggleSwitch.tsx
@@ -10,10 +10,7 @@ type Props = {
 };
 
 function ToggleSwitch({ options, value, name, onChange }: Props) {
-  const idxSelected = useMemo(
-    () => options.map((o) => o.value).indexOf(value),
-    [options, value]
-  );
+  const idxSelected = useMemo(() => options.map((o) => o.value).indexOf(value), [options, value]);
 
   const getPortionPercentage = useCallback(
     (idx: number) => {
diff --git a/src/components/TrafficChart.tsx b/src/components/TrafficChart.tsx
index 367166a..c6bf8ff 100644
--- a/src/components/TrafficChart.tsx
+++ b/src/components/TrafficChart.tsx
@@ -1,15 +1,11 @@
 import * as React from 'react';
 import { useTranslation } from 'react-i18next';
 
-import { State  } from '$src/store/types';
+import { State } from '$src/store/types';
 
 import { fetchData } from '../api/traffic';
 import useLineChart from '../hooks/useLineChart';
-import {
-  chartJSResource,
-  chartStyles,
-  commonDataSetProps,
-} from '../misc/chart';
+import { chartJSResource, chartStyles, commonDataSetProps } from '../misc/chart';
 import { getClashAPIConfig, getSelectedChartStyleIndex } from '../store/app';
 import { connect } from './StateProvider';
 
@@ -50,7 +46,7 @@ function TrafficChart({ apiConfig, selectedChartStyleIndex }) {
         },
       ],
     }),
-    [ traffic, selectedChartStyleIndex, t]
+    [traffic, selectedChartStyleIndex, t]
   );
 
   useLineChart(ChartMod.Chart, 'trafficChart', data, traffic);
diff --git a/src/components/about/About.tsx b/src/components/about/About.tsx
index 6ed01ad..f59ce20 100644
--- a/src/components/about/About.tsx
+++ b/src/components/about/About.tsx
@@ -11,15 +11,7 @@ import s from './About.module.scss';
 
 type Props = { apiConfig: ClashAPIConfig };
 
-function Version({
-  name,
-  link,
-  version,
-}: {
-  name: string;
-  link: string;
-  version: string;
-}) {
+function Version({ name, link, version }: { name: string; link: string; version: string }) {
   return (
     <div className={s.root}>
       <h2>{name}</h2>
@@ -28,12 +20,7 @@ function Version({
         <span className={s.mono}>{version}</span>
       </p>
       <p>
-        <a
-          className={s.link}
-          href={link}
-          target="_blank"
-          rel="noopener noreferrer"
-        >
+        <a className={s.link} href={link} target="_blank" rel="noopener noreferrer">
           <GitHub size={20} />
           <span>Source</span>
         </a>
@@ -50,17 +37,9 @@ function AboutImpl(props: Props) {
     <>
       <ContentHeader title="About" />
       {version && version.version ? (
-        <Version
-          name="Clash"
-          version={version.version}
-          link="https://github.com/Dreamacro/clash"
-        />
+        <Version name="Clash" version={version.version} link="https://github.com/Dreamacro/clash" />
       ) : null}
-      <Version
-        name="Yacd"
-        version={__VERSION__}
-        link="https://github.com/haishanh/yacd"
-      />
+      <Version name="Yacd" version={__VERSION__} link="https://github.com/haishanh/yacd" />
     </>
   );
 }
diff --git a/src/components/proxies/ClosePrevConns.tsx b/src/components/proxies/ClosePrevConns.tsx
index 5617efe..f26a5e9 100644
--- a/src/components/proxies/ClosePrevConns.tsx
+++ b/src/components/proxies/ClosePrevConns.tsx
@@ -10,10 +10,7 @@ type Props = {
   onClickSecondaryButton?: () => void;
 };
 
-export function ClosePrevConns({
-  onClickPrimaryButton,
-  onClickSecondaryButton,
-}: Props) {
+export function ClosePrevConns({ onClickPrimaryButton, onClickSecondaryButton }: Props) {
   const primaryButtonRef = useRef<HTMLButtonElement>(null);
   const secondaryButtonRef = useRef<HTMLButtonElement>(null);
   useEffect(() => {
@@ -33,8 +30,8 @@ export function ClosePrevConns({
     <div onKeyDown={handleKeyDown}>
       <h2>Close Connections?</h2>
       <p>
-        Click "Yes" to close those connections that are still using the old
-        selected proxy in this group
+        Click "Yes" to close those connections that are still using the old selected proxy in this
+        group
       </p>
       <div style={{ height: 30 }} />
       <FlexCenter>
diff --git a/src/components/proxies/Proxies.tsx b/src/components/proxies/Proxies.tsx
index c1606dd..12d3cb2 100644
--- a/src/components/proxies/Proxies.tsx
+++ b/src/components/proxies/Proxies.tsx
@@ -35,9 +35,7 @@ function Proxies({
   apiConfig,
   showModalClosePrevConns,
 }) {
-  const refFetchedTimestamp = useRef<{ startAt?: number; completeAt?: number }>(
-    {}
-  );
+  const refFetchedTimestamp = useRef<{ startAt?: number; completeAt?: number }>({});
 
   const fetchProxiesHooked = useCallback(() => {
     refFetchedTimestamp.current.startAt = Date.now();
@@ -75,10 +73,7 @@ function Proxies({
 
   return (
     <>
-      <BaseModal
-        isOpen={isSettingsModalOpen}
-        onRequestClose={closeSettingsModal}
-      >
+      <BaseModal isOpen={isSettingsModalOpen} onRequestClose={closeSettingsModal}>
         <Settings />
       </BaseModal>
       <div className={s0.topBar}>
@@ -110,15 +105,8 @@ function Proxies({
       </div>
       <ProxyProviderList items={proxyProviders} />
       <div style={{ height: 60 }} />
-      <ProxyPageFab
-        dispatch={dispatch}
-        apiConfig={apiConfig}
-        proxyProviders={proxyProviders}
-      />
-      <BaseModal
-        isOpen={showModalClosePrevConns}
-        onRequestClose={closeModalClosePrevConns}
-      >
+      <ProxyPageFab dispatch={dispatch} apiConfig={apiConfig} proxyProviders={proxyProviders} />
+      <BaseModal isOpen={showModalClosePrevConns} onRequestClose={closeModalClosePrevConns}>
         <ClosePrevConns
           onClickPrimaryButton={() => closePrevConnsAndTheModal(apiConfig)}
           onClickSecondaryButton={closeModalClosePrevConns}
diff --git a/src/components/proxies/Proxy.module.scss b/src/components/proxies/Proxy.module.scss
index b25948b..044722f 100644
--- a/src/components/proxies/Proxy.module.scss
+++ b/src/components/proxies/Proxy.module.scss
@@ -58,9 +58,6 @@
   width: 100%;
   margin-bottom: 5px;
   font-size: 0.85em;
-  @media (--breakpoint-not-small) {
-    font-size: 1em;
-  }
 }
 
 .proxySmall {
diff --git a/src/components/proxies/Proxy.tsx b/src/components/proxies/Proxy.tsx
index 424d320..8dc8caa 100644
--- a/src/components/proxies/Proxy.tsx
+++ b/src/components/proxies/Proxy.tsx
@@ -58,18 +58,8 @@ type ProxyProps = {
   onClick?: (proxyName: string) => unknown;
 };
 
-function ProxySmallImpl({
-  now,
-  name,
-  proxy,
-  latency,
-  isSelectable,
-  onClick,
-}: ProxyProps) {
-  const color = useMemo(() => getProxyDotBackgroundColor(latency, proxy.type), [
-    latency,
-    proxy,
-  ]);
+function ProxySmallImpl({ now, name, proxy, latency, isSelectable, onClick }: ProxyProps) {
+  const color = useMemo(() => getProxyDotBackgroundColor(latency, proxy.type), [latency, proxy]);
   const title = useMemo(() => {
     let ret = name;
     if (latency && typeof latency.number === 'number') {
@@ -115,14 +105,7 @@ function formatProxyType(t: string) {
   return t;
 }
 
-function ProxyImpl({
-  now,
-  name,
-  proxy,
-  latency,
-  isSelectable,
-  onClick,
-}: ProxyProps) {
+function ProxyImpl({ now, name, proxy, latency, isSelectable, onClick }: ProxyProps) {
   const color = useMemo(() => getLabelColor(latency), [latency]);
   const doSelect = React.useCallback(() => {
     isSelectable && onClick && onClick(name);
@@ -156,9 +139,7 @@ function ProxyImpl({
         <span className={s0.proxyType} style={{ opacity: now ? 0.6 : 0.2 }}>
           {formatProxyType(proxy.type)}
         </span>
-        {latency && latency.number ? (
-          <ProxyLatency number={latency.number} color={color} />
-        ) : null}
+        {latency && latency.number ? <ProxyLatency number={latency.number} color={color} /> : null}
       </div>
     </div>
   );
diff --git a/src/components/proxies/ProxyGroup.module.scss b/src/components/proxies/ProxyGroup.module.scss
index 5409ea8..6e9d91f 100644
--- a/src/components/proxies/ProxyGroup.module.scss
+++ b/src/components/proxies/ProxyGroup.module.scss
@@ -2,6 +2,15 @@
   margin-bottom: 12px;
 }
 
+.groupHead {
+  display: flex;
+  align-items: center;
+}
+
+.latencyButton {
+  margin-left: 5px;
+}
+
 .zapWrapper {
   width: 20px;
   height: 20px;
diff --git a/src/components/proxies/ProxyGroup.tsx b/src/components/proxies/ProxyGroup.tsx
index 32705c1..d6a4e99 100644
--- a/src/components/proxies/ProxyGroup.tsx
+++ b/src/components/proxies/ProxyGroup.tsx
@@ -1,11 +1,9 @@
 import * as React from 'react';
 import { Zap } from 'react-feather';
 
-import {
-  getCollapsibleIsOpen,
-  getHideUnavailableProxies,
-  getProxySortBy,
-} from '../../store/app';
+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';
@@ -37,13 +35,7 @@ function ProxyGroupImpl({
   apiConfig,
   dispatch,
 }) {
-  const all = useFilteredAndSorted(
-    allItems,
-    delay,
-    hideUnavailableProxies,
-    proxySortBy,
-    proxies
-  );
+  const all = useFilteredAndSorted(allItems, delay, hideUnavailableProxies, proxySortBy, proxies);
 
   const isSelectable = useMemo(() => type === 'Selector', [type]);
 
@@ -57,7 +49,7 @@ function ProxyGroupImpl({
   }, [isOpen, updateCollapsibleIsOpen, name]);
 
   const itemOnTapCallback = useCallback(
-    (proxyName) => {
+    (proxyName: string) => {
       if (!isSelectable) return;
       dispatch(switchProxy(apiConfig, name, proxyName));
     },
@@ -75,7 +67,7 @@ function ProxyGroupImpl({
 
   return (
     <div className={s0.group}>
-      <div style={{ display: 'flex', alignItems: 'center' }}>
+      <div className={s0.groupHead}>
         <CollapsibleSectionHeader
           name={name}
           type={type}
@@ -84,6 +76,7 @@ function ProxyGroupImpl({
           isOpen={isOpen}
         />
         <Button
+          className={s0.latencyButton}
           title="Test latency"
           kind="minimal"
           onClick={testLatency}
@@ -102,7 +95,7 @@ function ProxyGroupImpl({
   );
 }
 
-export const ProxyGroup = connect((s, { name, delay }) => {
+export const ProxyGroup = connect((s: State, { name, delay }) => {
   const proxies = getProxies(s);
   const collapsibleIsOpen = getCollapsibleIsOpen(s);
   const proxySortBy = getProxySortBy(s);
diff --git a/src/components/proxies/ProxyList.tsx b/src/components/proxies/ProxyList.tsx
index a86bb88..3856c68 100644
--- a/src/components/proxies/ProxyList.tsx
+++ b/src/components/proxies/ProxyList.tsx
@@ -11,12 +11,7 @@ type ProxyListProps = {
   show?: boolean;
 };
 
-export function ProxyList({
-  all,
-  now,
-  isSelectable,
-  itemOnTapCallback,
-}: ProxyListProps) {
+export function ProxyList({ all, now, isSelectable, itemOnTapCallback }: ProxyListProps) {
   const proxies = all;
 
   return (
diff --git a/src/components/proxies/ProxyPageFab.tsx b/src/components/proxies/ProxyPageFab.tsx
index 7cc6d03..44e446f 100644
--- a/src/components/proxies/ProxyPageFab.tsx
+++ b/src/components/proxies/ProxyPageFab.tsx
@@ -2,12 +2,7 @@ import * as React from 'react';
 import { Zap } from 'react-feather';
 import { useTranslation } from 'react-i18next';
 import { useUpdateProviderItems } from 'src/components/proxies/proxies.hooks';
-import {
-  Action,
-  Fab,
-  IsFetching,
-  position as fabPosition,
-} from 'src/components/shared/Fab';
+import { Action, Fab, IsFetching, position as fabPosition } from 'src/components/shared/Fab';
 import { RotateIcon } from 'src/components/shared/RotateIcon';
 import { requestDelayAll } from 'src/store/proxies';
 import { DispatchFn, FormattedProxyProvider } from 'src/store/types';
diff --git a/src/components/proxies/ProxyProvider.tsx b/src/components/proxies/ProxyProvider.tsx
index 055a572..af5be18 100644
--- a/src/components/proxies/ProxyProvider.tsx
+++ b/src/components/proxies/ProxyProvider.tsx
@@ -48,12 +48,7 @@ function ProxyProviderImpl({
   dispatch,
   apiConfig,
 }: Props) {
-  const proxies = useFilteredAndSorted(
-    all,
-    delay,
-    hideUnavailableProxies,
-    proxySortBy
-  );
+  const proxies = useFilteredAndSorted(all, delay, hideUnavailableProxies, proxySortBy);
   const [isHealthcheckLoading, setIsHealthcheckLoading] = useState(false);
 
   const updateProvider = useUpdateProviderItem({ dispatch, apiConfig, name });
diff --git a/src/components/proxies/ProxyProviderList.tsx b/src/components/proxies/ProxyProviderList.tsx
index 1528f37..754eeac 100644
--- a/src/components/proxies/ProxyProviderList.tsx
+++ b/src/components/proxies/ProxyProviderList.tsx
@@ -3,11 +3,7 @@ import ContentHeader from 'src/components/ContentHeader';
 import { ProxyProvider } from 'src/components/proxies/ProxyProvider';
 import { FormattedProxyProvider } from 'src/store/types';
 
-export function ProxyProviderList({
-  items,
-}: {
-  items: FormattedProxyProvider[];
-}) {
+export function ProxyProviderList({ items }: { items: FormattedProxyProvider[] }) {
   if (items.length === 0) return null;
 
   return (
diff --git a/src/components/proxies/Settings.tsx b/src/components/proxies/Settings.tsx
index 5e1ff98..55e18fe 100644
--- a/src/components/proxies/Settings.tsx
+++ b/src/components/proxies/Settings.tsx
@@ -2,11 +2,7 @@ import * as React from 'react';
 import { useTranslation } from 'react-i18next';
 import Select from 'src/components/shared/Select';
 
-import {
-  getAutoCloseOldConns,
-  getHideUnavailableProxies,
-  getProxySortBy,
-} from '../../store/app';
+import { getAutoCloseOldConns, getHideUnavailableProxies, getProxySortBy } from '../../store/app';
 import { connect, useStoreActions } from '../StateProvider';
 import Switch from '../SwitchThemed';
 import s from './Settings.module.scss';
diff --git a/src/components/proxies/hooks.tsx b/src/components/proxies/hooks.tsx
index 861c0e5..a43dc0e 100644
--- a/src/components/proxies/hooks.tsx
+++ b/src/components/proxies/hooks.tsx
@@ -45,22 +45,14 @@ const getSortDelay = (
 
 const ProxySortingFns = {
   Natural: (proxies: string[]) => proxies,
-  LatencyAsc: (
-    proxies: string[],
-    delay: DelayMapping,
-    proxyMapping?: ProxiesMapping
-  ) => {
+  LatencyAsc: (proxies: string[], delay: DelayMapping, proxyMapping?: ProxiesMapping) => {
     return proxies.sort((a, b) => {
       const d1 = getSortDelay(delay[a], proxyMapping && proxyMapping[a]);
       const d2 = getSortDelay(delay[b], proxyMapping && proxyMapping[b]);
       return d1 - d2;
     });
   },
-  LatencyDesc: (
-    proxies: string[],
-    delay: DelayMapping,
-    proxyMapping?: ProxiesMapping
-  ) => {
+  LatencyDesc: (proxies: string[], delay: DelayMapping, proxyMapping?: ProxiesMapping) => {
     return proxies.sort((a, b) => {
       const d1 = getSortDelay(delay[a], proxyMapping && proxyMapping[a]);
       const d2 = getSortDelay(delay[b], proxyMapping && proxyMapping[b]);
diff --git a/src/components/proxies/proxies.hooks.tsx b/src/components/proxies/proxies.hooks.tsx
index ec51c9b..20695ac 100644
--- a/src/components/proxies/proxies.hooks.tsx
+++ b/src/components/proxies/proxies.hooks.tsx
@@ -14,11 +14,10 @@ export function useUpdateProviderItem({
   apiConfig: ClashAPIConfig;
   name: string;
 }) {
-  return useCallback(() => dispatch(updateProviderByName(apiConfig, name)), [
-    apiConfig,
-    dispatch,
-    name,
-  ]);
+  return useCallback(
+    () => dispatch(updateProviderByName(apiConfig, name)),
+    [apiConfig, dispatch, name]
+  );
 }
 
 export function useUpdateProviderItems({
diff --git a/src/components/rules/RuleProviderItem.module.scss b/src/components/rules/RuleProviderItem.module.scss
index 532ec8a..c3e1f07 100644
--- a/src/components/rules/RuleProviderItem.module.scss
+++ b/src/components/rules/RuleProviderItem.module.scss
@@ -13,6 +13,7 @@
 
 .middle {
   display: grid;
+  gap: 6px;
   grid-template-rows: 1fr auto auto;
   align-items: center;
 }
@@ -21,13 +22,13 @@
   color: #777;
 }
 
-.refreshButtonWrapper {
+.action {
   display: grid;
-  place-items: center;
-  opacity: 0;
-  transition: opacity 0.2s;
+  gap: 4px;
+  grid-template-columns: auto 1fr;
+  align-items: center;
 }
 
-.RuleProviderItem:hover .refreshButtonWrapper {
-  opacity: 1;
+.refreshBtn {
+  padding: 5px;
 }
diff --git a/src/components/rules/RuleProviderItem.tsx b/src/components/rules/RuleProviderItem.tsx
index fc88ae1..c27e464 100644
--- a/src/components/rules/RuleProviderItem.tsx
+++ b/src/components/rules/RuleProviderItem.tsx
@@ -24,14 +24,14 @@ export function RuleProviderItem({
       <div className={s.middle}>
         <SectionNameType name={name} type={`${vehicleType} / ${behavior}`} />
         <div className={s.gray}>{ruleCount < 2 ? `${ruleCount} rule` : `${ruleCount} rules`}</div>
-        <small className={s.gray}>Updated {timeAgo} ago</small>
+        <div className={s.action}>
+          <Button onClick={onClickRefreshButton} disabled={isRefreshing} className={s.refreshBtn}>
+            <RotateIcon isRotating={isRefreshing} size={13} />
+            <span className="visually-hidden">Refresh</span>
+          </Button>
+          <small className={s.gray}>Updated {timeAgo} ago</small>
+        </div>
       </div>
-      <span className={s.refreshButtonWrapper}>
-        <Button onClick={onClickRefreshButton} disabled={isRefreshing} kind="circular">
-          <RotateIcon isRotating={isRefreshing} />
-          <span className="visually-hidden">Refresh</span>
-        </Button>
-      </span>
     </div>
   );
 }
diff --git a/src/components/shared/Fab.tsx b/src/components/shared/Fab.tsx
index 832306e..8e72432 100644
--- a/src/components/shared/Fab.tsx
+++ b/src/components/shared/Fab.tsx
@@ -28,8 +28,7 @@ const AB: React.FC<ABProps> = ({ children, ...p }) => (
   </button>
 );
 
-interface MBProps
-  extends Omit<React.HTMLAttributes<HTMLButtonElement>, 'tabIndex'> {
+interface MBProps extends Omit<React.HTMLAttributes<HTMLButtonElement>, 'tabIndex'> {
   tabIndex?: number;
 }
 
@@ -77,10 +76,7 @@ const Fab: React.FC<FabProps> = ({
     return event === 'click' ? (isOpen ? close() : open()) : null;
   };
 
-  const actionOnClick = (
-    e: React.FormEvent,
-    userFunc: (e: React.FormEvent) => void
-  ) => {
+  const actionOnClick = (e: React.FormEvent, userFunc: (e: React.FormEvent) => void) => {
     e.persist();
     setIsOpen(false);
     setTimeout(() => {
@@ -141,9 +137,7 @@ const Fab: React.FC<FabProps> = ({
         </MB>
         {text && (
           <span
-            className={`${'right' in style ? 'right' : ''} ${
-              alwaysShowTitle ? 'always-show' : ''
-            }`}
+            className={`${'right' in style ? 'right' : ''} ${alwaysShowTitle ? 'always-show' : ''}`}
             aria-hidden={ariaHidden}
           >
             {text}
diff --git a/src/components/shared/RotateIcon.tsx b/src/components/shared/RotateIcon.tsx
index d9dcbd9..d291ece 100644
--- a/src/components/shared/RotateIcon.tsx
+++ b/src/components/shared/RotateIcon.tsx
@@ -4,13 +4,12 @@ import { RotateCw } from 'react-feather';
 
 import s from './RotateIcon.module.scss';
 
-export function RotateIcon({ isRotating }: { isRotating: boolean }) {
-  const cls = cx(s.rotate, {
-    [s.isRotating]: isRotating,
-  });
+export function RotateIcon(props: { isRotating: boolean; size?: number }) {
+  const size = props.size || 16;
+  const cls = cx(s.rotate, { [s.isRotating]: props.isRotating });
   return (
     <span className={cls}>
-      <RotateCw size={16} />
+      <RotateCw size={size} />
     </span>
   );
 }
diff --git a/src/components/shared/TextFitler.tsx b/src/components/shared/TextFitler.tsx
index e4a4a88..7af61ac 100644
--- a/src/components/shared/TextFitler.tsx
+++ b/src/components/shared/TextFitler.tsx
@@ -4,10 +4,7 @@ import { useTextInut } from 'src/hooks/useTextInput';
 
 import s from './TextFitler.module.scss';
 
-export function TextFilter(props: {
-  textAtom: RecoilState<string>;
-  placeholder?: string;
-}) {
+export function TextFilter(props: { textAtom: RecoilState<string>; placeholder?: string }) {
   const [onChange, text] = useTextInut(props.textAtom);
   return (
     <input
diff --git a/src/components/svg/Equalizer.tsx b/src/components/svg/Equalizer.tsx
index 274720f..ae3c858 100644
--- a/src/components/svg/Equalizer.tsx
+++ b/src/components/svg/Equalizer.tsx
@@ -5,10 +5,7 @@ type Props = {
   color?: string;
 };
 
-export default function Equalizer({
-  color = 'currentColor',
-  size = 24,
-}: Props) {
+export default function Equalizer({ color = 'currentColor', size = 24 }: Props) {
   return (
     <svg
       fill="none"
diff --git a/src/hooks/useRemainingViewPortHeight.ts b/src/hooks/useRemainingViewPortHeight.ts
index 9f3470d..2c920c2 100644
--- a/src/hooks/useRemainingViewPortHeight.ts
+++ b/src/hooks/useRemainingViewPortHeight.ts
@@ -9,9 +9,10 @@ const { useState, useRef, useCallback, useLayoutEffect } = React;
  * to the bottom of the view port
  *
  */
-export default function useRemainingViewPortHeight<
-  ElementType extends HTMLDivElement
->(): [React.MutableRefObject<ElementType>, number] {
+export default function useRemainingViewPortHeight<ElementType extends HTMLDivElement>(): [
+  React.MutableRefObject<ElementType>,
+  number
+] {
   const ref = useRef<ElementType>(null);
   const [containerHeight, setContainerHeight] = useState(200);
   const updateContainerHeight = useCallback(() => {
diff --git a/src/hooks/useTextInput.ts b/src/hooks/useTextInput.ts
index 1fa19f7..853044c 100644
--- a/src/hooks/useTextInput.ts
+++ b/src/hooks/useTextInput.ts
@@ -9,9 +9,7 @@ export function useTextInut(
 ): [(e: React.ChangeEvent<HTMLInputElement>) => void, string] {
   const [, setTextGlobal] = useRecoilState(x);
   const [text, setText] = useState('');
-  const setTextDebounced = useMemo(() => debounce(setTextGlobal, 300), [
-    setTextGlobal,
-  ]);
+  const setTextDebounced = useMemo(() => debounce(setTextGlobal, 300), [setTextGlobal]);
   const onChange = useCallback(
     (e: React.ChangeEvent<HTMLInputElement>) => {
       setText(e.target.value);
diff --git a/src/misc/chart.ts b/src/misc/chart.ts
index c62fa06..56e05a2 100644
--- a/src/misc/chart.ts
+++ b/src/misc/chart.ts
@@ -1,4 +1,4 @@
-import { createAsset } from "use-asset"
+import { createAsset } from 'use-asset';
 
 import prettyBytes from './pretty-bytes';
 export const chartJSResource = createAsset(() => {
@@ -11,7 +11,7 @@ export const commonChartOptions: import('chart.js').ChartOptions<'line'> = {
   responsive: true,
   maintainAspectRatio: true,
   plugins: {
-    legend: { labels: { boxWidth: 20 } }
+    legend: { labels: { boxWidth: 20 } },
   },
   scales: {
     x: { display: false, type: 'category' },
diff --git a/src/misc/i18n.ts b/src/misc/i18n.ts
index cf1a4f2..eecd72a 100644
--- a/src/misc/i18n.ts
+++ b/src/misc/i18n.ts
@@ -8,10 +8,7 @@ const allLocales = {
   en: import('src/i18n/en'),
 };
 
-type BackendRequestCallback = (
-  err: null,
-  result: { status: number; data: any }
-) => void;
+type BackendRequestCallback = (err: null, result: { status: number; data: any }) => void;
 
 i18next
   .use(HttpBackend)
diff --git a/src/misc/motion.ts b/src/misc/motion.ts
index 5f2fe50..7fac864 100644
--- a/src/misc/motion.ts
+++ b/src/misc/motion.ts
@@ -1,5 +1,3 @@
 import { createResource } from './createResource';
 
-export const framerMotionResouce = createResource(
-  () => import('framer-motion')
-);
+export const framerMotionResouce = createResource(() => import('framer-motion'));
diff --git a/src/misc/request-helper.ts b/src/misc/request-helper.ts
index 3bc8476..c01b994 100644
--- a/src/misc/request-helper.ts
+++ b/src/misc/request-helper.ts
@@ -12,7 +12,7 @@ function genCommonHeaders({ secret }: { secret?: string }) {
   return h;
 }
 function buildWebSocketURLBase(baseURL: string, params: URLSearchParams, endpoint: string) {
-  const qs = '?' + params.toString()
+  const qs = '?' + params.toString();
   const url = new URL(baseURL);
   url.protocol === 'https:' ? (url.protocol = 'wss:') : (url.protocol = 'ws:');
   return `${trimTrailingSlash(url.href)}${endpoint}${qs}`;
@@ -32,7 +32,7 @@ export function buildWebSocketURL(apiConfig: ClashAPIConfig, endpoint: string) {
     token: secret,
   });
 
-  return buildWebSocketURLBase(baseURL, params, endpoint)
+  return buildWebSocketURLBase(baseURL, params, endpoint);
 }
 
 export function buildLogsWebSocketURL(apiConfig: LogsAPIConfig, endpoint: string) {
@@ -42,5 +42,5 @@ export function buildLogsWebSocketURL(apiConfig: LogsAPIConfig, endpoint: string
     level: logLevel,
   });
 
-  return buildWebSocketURLBase(baseURL, params, endpoint)
+  return buildWebSocketURLBase(baseURL, params, endpoint);
 }
diff --git a/src/misc/shallowEqual.ts b/src/misc/shallowEqual.ts
index 241b725..937bc27 100644
--- a/src/misc/shallowEqual.ts
+++ b/src/misc/shallowEqual.ts
@@ -12,12 +12,7 @@ function is(x, y) {
 export default function shallowEqual(objA, objB) {
   if (is(objA, objB)) return true;
 
-  if (
-    typeof objA !== 'object' ||
-    objA === null ||
-    typeof objB !== 'object' ||
-    objB === null
-  ) {
+  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
     return false;
   }
 
diff --git a/src/misc/utils.ts b/src/misc/utils.ts
index d3a7bfc..9497026 100644
--- a/src/misc/utils.ts
+++ b/src/misc/utils.ts
@@ -1,7 +1,4 @@
-export function throttle<T extends any[]>(
-  fn: (...args: T) => unknown,
-  timeout: number
-) {
+export function throttle<T extends any[]>(fn: (...args: T) => unknown, timeout: number) {
   let pending = false;
 
   return (...args: T) => {
@@ -15,10 +12,7 @@ export function throttle<T extends any[]>(
   };
 }
 
-export function debounce<T extends any[]>(
-  fn: (...args: T) => unknown,
-  timeout: number
-) {
+export function debounce<T extends any[]>(fn: (...args: T) => unknown, timeout: number) {
   let timeoutId: ReturnType<typeof setTimeout>;
   return (...args: T) => {
     if (timeoutId) clearTimeout(timeoutId);
diff --git a/src/store/app.ts b/src/store/app.ts
index 7262b32..2789981 100644
--- a/src/store/app.ts
+++ b/src/store/app.ts
@@ -152,7 +152,7 @@ export function updateCollapsibleIsOpen(prefix: string, name: string, v: boolean
 const defaultClashAPIConfig = {
   baseURL: document.getElementById('app')?.getAttribute('data-base-url') ?? 'http://127.0.0.1:9090',
   secret: '',
-  addedAt: 0
+  addedAt: 0,
 };
 // type Theme = 'light' | 'dark';
 const defaultState: StateApp = {
@@ -169,7 +169,7 @@ const defaultState: StateApp = {
   proxySortBy: 'Natural',
   hideUnavailableProxies: false,
   autoCloseOldConns: false,
-  logStreamingPaused: false
+  logStreamingPaused: false,
 };
 
 function parseConfigQueryString() {
diff --git a/src/store/configs.ts b/src/store/configs.ts
index c533508..7571b4e 100644
--- a/src/store/configs.ts
+++ b/src/store/configs.ts
@@ -1,10 +1,4 @@
-import {
-  ClashGeneralConfig,
-  DispatchFn,
-  GetStateFn,
-  State,
-  StateConfigs,
-} from 'src/store/types';
+import { ClashGeneralConfig, DispatchFn, GetStateFn, State, StateConfigs } from 'src/store/types';
 import { ClashAPIConfig } from 'src/types';
 
 import * as configsAPI from '../api/configs';
diff --git a/src/store/proxies.tsx b/src/store/proxies.tsx
index 25200cd..0505fce 100644
--- a/src/store/proxies.tsx
+++ b/src/store/proxies.tsx
@@ -48,8 +48,7 @@ export const getDelay = (s: State) => s.proxies.delay;
 export const getProxyGroupNames = (s: State) => s.proxies.groupNames;
 export const getProxyProviders = (s: State) => s.proxies.proxyProviders || [];
 export const getDangleProxyNames = (s: State) => s.proxies.dangleProxyNames;
-export const getShowModalClosePrevConns = (s: State) =>
-  s.proxies.showModalClosePrevConns;
+export const getShowModalClosePrevConns = (s: State) => s.proxies.showModalClosePrevConns;
 
 export function fetchProxies(apiConfig: ClashAPIConfig) {
   return async (dispatch: any, getState: any) => {
@@ -58,10 +57,9 @@ export function fetchProxies(apiConfig: ClashAPIConfig) {
       proxiesAPI.fetchProviderProxies(apiConfig),
     ]);
 
-    const {
-      providers: proxyProviders,
-      proxies: providerProxies,
-    } = formatProxyProviders(providersData.providers);
+    const { providers: proxyProviders, proxies: providerProxies } = formatProxyProviders(
+      providersData.providers
+    );
     const proxies = { ...providerProxies, ...proxiesData.proxies };
     const [groupNames, proxyNames] = retrieveGroupNamesFrom(proxies);
 
@@ -121,10 +119,7 @@ export function updateProviders(apiConfig: ClashAPIConfig, names: string[]) {
   };
 }
 
-async function healthcheckProviderByNameInternal(
-  apiConfig: ClashAPIConfig,
-  name: string
-) {
+async function healthcheckProviderByNameInternal(apiConfig: ClashAPIConfig, name: string) {
   try {
     await proxiesAPI.healthcheckProviderByName(apiConfig, name);
   } catch (x) {
@@ -132,10 +127,7 @@ async function healthcheckProviderByNameInternal(
   }
 }
 
-export function healthcheckProviderByName(
-  apiConfig: ClashAPIConfig,
-  name: string
-) {
+export function healthcheckProviderByName(apiConfig: ClashAPIConfig, name: string) {
   return async (dispatch: DispatchFn) => {
     await healthcheckProviderByNameInternal(apiConfig, name);
     // should be optimized
@@ -168,16 +160,10 @@ async function closeGroupConns(
     }
   }
 
-  await Promise.all(
-    idsToClose.map((id) => connAPI.closeConnById(apiConfig, id).catch(noop))
-  );
+  await Promise.all(idsToClose.map((id) => connAPI.closeConnById(apiConfig, id).catch(noop)));
 }
 
-function resolveChain(
-  proxies: ProxiesMapping,
-  groupName: string,
-  itemName: string
-) {
+function resolveChain(proxies: ProxiesMapping, groupName: string, itemName: string) {
   const chain = [itemName, groupName];
 
   let child: ProxyItem;
@@ -197,11 +183,7 @@ async function switchProxyImpl(
   itemName: string
 ) {
   try {
-    const res = await proxiesAPI.requestToSwitchProxy(
-      apiConfig,
-      groupName,
-      itemName
-    );
+    const res = await proxiesAPI.requestToSwitchProxy(apiConfig, groupName, itemName);
     if (res.ok === false) {
       throw new Error(`failed to switch proxy: res.statusText`);
     }
@@ -267,16 +249,10 @@ function closePrevConnsAndTheModal(apiConfig: ClashAPIConfig) {
   };
 }
 
-export function switchProxy(
-  apiConfig: ClashAPIConfig,
-  groupName: string,
-  itemName: string
-) {
+export function switchProxy(apiConfig: ClashAPIConfig, groupName: string, itemName: string) {
   return async (dispatch: DispatchFn, getState: GetStateFn) => {
     // switch proxy asynchronously
-    switchProxyImpl(dispatch, getState, apiConfig, groupName, itemName).catch(
-      noop
-    );
+    switchProxyImpl(dispatch, getState, apiConfig, groupName, itemName).catch(noop);
 
     // optimistic UI update
     dispatch('store/proxies#switchProxy', (s) => {
@@ -291,11 +267,7 @@ export function switchProxy(
 function requestDelayForProxyOnce(apiConfig: ClashAPIConfig, name: string) {
   return async (dispatch: DispatchFn, getState: GetStateFn) => {
     const latencyTestUrl = getLatencyTestUrl(getState());
-    const res = await proxiesAPI.requestDelayForProxy(
-      apiConfig,
-      name,
-      latencyTestUrl
-    );
+    const res = await proxiesAPI.requestDelayForProxy(apiConfig, name, latencyTestUrl);
     let error = '';
     if (res.ok === false) {
       error = res.statusText;
@@ -323,10 +295,7 @@ export function requestDelayForProxy(apiConfig: ClashAPIConfig, name: string) {
   };
 }
 
-export function requestDelayForProxies(
-  apiConfig: ClashAPIConfig,
-  names: string[]
-) {
+export function requestDelayForProxies(apiConfig: ClashAPIConfig, names: string[]) {
   return async (dispatch: DispatchFn, getState: GetStateFn) => {
     const proxyNames = getDangleProxyNames(getState());
 
@@ -342,9 +311,7 @@ export function requestDelayForProxies(
 export function requestDelayAll(apiConfig: ClashAPIConfig) {
   return async (dispatch: DispatchFn, getState: GetStateFn) => {
     const proxyNames = getDangleProxyNames(getState());
-    await Promise.all(
-      proxyNames.map((p) => dispatch(requestDelayForProxy(apiConfig, p)))
-    );
+    await Promise.all(proxyNames.map((p) => dispatch(requestDelayForProxy(apiConfig, p))));
     const proxyProviders = getProxyProviders(getState());
     // one by one
     for (const p of proxyProviders) {
@@ -385,9 +352,7 @@ type ProvidersRaw = {
   [key: string]: ProxyProvider;
 };
 
-function formatProxyProviders(
-  providersInput: ProvidersRaw
-): {
+function formatProxyProviders(providersInput: ProvidersRaw): {
   providers: Array<FormattedProxyProvider>;
   proxies: { [key: string]: ProxyItem };
 } {
diff --git a/src/sw.ts b/src/sw.ts
index bdc663c..f577677 100644
--- a/src/sw.ts
+++ b/src/sw.ts
@@ -53,8 +53,7 @@ registerRoute(
 // precache, in this case same-origin .png requests like those from in public/
 registerRoute(
   // Add in any other file extensions or routing criteria as needed.
-  ({ url }) =>
-    url.origin === self.location.origin && url.pathname.endsWith('.png'),
+  ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'),
   // Customize this strategy as needed, e.g., by changing to CacheFirst.
   new StaleWhileRevalidate({
     cacheName: 'images',
diff --git a/src/swRegistration.ts b/src/swRegistration.ts
index 55ceb0b..0a684a8 100644
--- a/src/swRegistration.ts
+++ b/src/swRegistration.ts
@@ -3,9 +3,7 @@ const isLocalhost = Boolean(
     // [::1] is the IPv6 localhost address.
     window.location.hostname === '[::1]' ||
     // 127.0.0.0/8 are considered localhost for IPv4.
-    window.location.hostname.match(
-      /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
-    )
+    window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
 );
 
 type Config = {
@@ -34,9 +32,7 @@ export function register(config?: Config) {
         // Add some additional logging to localhost, pointing developers to the
         // service worker/PWA documentation.
         navigator.serviceWorker.ready.then(() => {
-          console.log(
-            'This web app is being served cache-first by a service worker'
-          );
+          console.log('This web app is being served cache-first by a service worker');
         });
       } else {
         // Is not localhost. Just register service worker
@@ -114,9 +110,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
       }
     })
     .catch(() => {
-      console.log(
-        'No internet connection found. App is running in offline mode.'
-      );
+      console.log('No internet connection found. App is running in offline mode.');
     });
 }
 
diff --git a/src/types.ts b/src/types.ts
index 694289b..8446dfc 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -3,4 +3,4 @@ export type ClashAPIConfig = {
   secret?: string;
 };
 
-export type LogsAPIConfig = ClashAPIConfig & { logLevel: string };
\ No newline at end of file
+export type LogsAPIConfig = ClashAPIConfig & { logLevel: string };
-- 
cgit v1.3.1

