summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaishan <[email protected]>2020-09-13 16:34:18 +0800
committerHaishan <[email protected]>2020-09-13 17:16:14 +0800
commit15bc0f69a8367a57fa1bf263e615285349ad4ab9 (patch)
treefbdd2a46303703822f7e7bc3462a70b4855fe4a1
parenta8f0d3d4b4928caebf61c75fa9191a170b471035 (diff)
feat: multi backends management
-rw-r--r--.eslintrc.yml1
-rw-r--r--package.json24
-rw-r--r--src/components/APIConfig.module.css2
-rw-r--r--src/components/APIConfig.tsx24
-rw-r--r--src/components/APIDiscovery.module.css2
-rw-r--r--src/components/BackendList.module.css99
-rw-r--r--src/components/BackendList.tsx147
-rw-r--r--src/components/Config.js8
-rw-r--r--src/components/ErrorBoundary.js40
-rw-r--r--src/components/Root.js58
-rw-r--r--src/components/TrafficChart.js3
-rw-r--r--src/store/app.js108
-rw-r--r--src/store/configs.js33
-rw-r--r--src/store/index.js4
-rw-r--r--yarn.lock180
15 files changed, 516 insertions, 217 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index c98f60c..de8d215 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -27,6 +27,7 @@ rules:
'@typescript-eslint/explicit-function-return-type': 'off'
'@typescript-eslint/no-explicit-any': 'off'
'@typescript-eslint/camelcase': 'off'
+ 'no-use-before-define': 'off'
'@typescript-eslint/no-unused-vars':
- 'error'
- argsIgnorePattern: '^_'
diff --git a/package.json b/package.json
index 64d17ee..3f70b43 100644
--- a/package.json
+++ b/package.json
@@ -34,14 +34,14 @@
"dependencies": {
"@babel/runtime": "^7.11.2",
"@hsjs/react-cache": "0.0.0-alpha.aa94237",
- "@sentry/browser": "^5.22.3",
+ "@sentry/browser": "^5.23.0",
"chart.js": "^2.9.2",
"clsx": "^1.1.0",
"core-js": "^3.6.2",
"date-fns": "^2.16.0",
- "framer-motion": "^2.6.7",
+ "framer-motion": "^2.6.13",
"history": "^5.0.0",
- "immer": "^7.0.8",
+ "immer": "^7.0.9",
"invariant": "^2.2.4",
"lodash-es": "^4.17.14",
"memoize-one": "^5.1.1",
@@ -52,7 +52,7 @@
"react-feather": "^2.0.3",
"react-icons": "^3.10.0",
"react-modal": "^3.11.1",
- "react-query": "^2.15.4",
+ "react-query": "^2.17.0",
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
"react-switch": "^5.0.1",
@@ -92,37 +92,37 @@
"copy-webpack-plugin": "^6.0.4",
"css-loader": "^4.3.0",
"cssnano": "^4.1.7",
- "eslint": "^7.6.0",
+ "eslint": "^7.9.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-config-prettier": "^6.11.0",
"eslint-config-react-app": "^5.2.1",
"eslint-import-resolver-webpack": "^0.12.2",
- "eslint-plugin-flowtype": "^5.1.0",
+ "eslint-plugin-flowtype": "^5.2.0",
"eslint-plugin-import": "^2.22.0",
- "eslint-plugin-jest": "^24.0.0",
+ "eslint-plugin-jest": "^24.0.1",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.20.6",
- "eslint-plugin-react-hooks": "^4.0.8",
+ "eslint-plugin-react-hooks": "^4.1.2",
"eslint-plugin-simple-import-sort": "^5.0.3",
"file-loader": "^6.0.0",
"fork-ts-checker-notifier-webpack-plugin": "^3.0.0",
- "fork-ts-checker-webpack-plugin": "^5.0.14",
+ "fork-ts-checker-webpack-plugin": "^5.2.0",
"html-webpack-plugin": "^4.3.0",
"husky": "^4.3.0",
"lint-staged": "^10.2.13",
- "mini-css-extract-plugin": "^0.11.0",
+ "mini-css-extract-plugin": "^0.11.2",
"postcss": "^7.0.32",
"postcss-custom-media": "^7.0.8",
"postcss-extend-rule": "^3.0.0",
"postcss-import": "^12.0.1",
- "postcss-loader": "^4.0.0",
+ "postcss-loader": "^4.0.1",
"postcss-nested": "^4.2.3",
"postcss-simple-vars": "^5.0.2",
"prettier": "^2.1.1",
"react-refresh": "^0.8.2",
"resize-observer-polyfill": "^1.5.1",
"style-loader": "^1.2.1",
- "terser-webpack-plugin": "^4.1.0",
+ "terser-webpack-plugin": "^4.2.0",
"ts-loader": "^8.0.3",
"typescript": "^4.0.2",
"webpack": "^4.44.1",
diff --git a/src/components/APIConfig.module.css b/src/components/APIConfig.module.css
index 1092aed..afc2d53 100644
--- a/src/components/APIConfig.module.css
+++ b/src/components/APIConfig.module.css
@@ -20,7 +20,7 @@
}
.body {
- padding: 30px 0 0;
+ padding: 15px 0 0;
}
.hostnamePort {
diff --git a/src/components/APIConfig.tsx b/src/components/APIConfig.tsx
index 88bec8b..3befa5c 100644
--- a/src/components/APIConfig.tsx
+++ b/src/components/APIConfig.tsx
@@ -1,8 +1,9 @@
import * as React from 'react';
import { fetchConfigs } from 'src/api/configs';
+import { BackendList } from 'src/components/BackendList';
import { ClashAPIConfig } from 'src/types';
-import { getClashAPIConfig, updateClashAPIConfig } from '../store/app';
+import { addClashAPIConfig, getClashAPIConfig } from '../store/app';
import s0 from './APIConfig.module.css';
import Button from './Button';
import Field from './Field';
@@ -16,9 +17,9 @@ const mapState = (s) => ({
apiConfig: getClashAPIConfig(s),
});
-function APIConfig({ apiConfig, dispatch }) {
- const [baseURL, setBaseURL] = useState(apiConfig.baseURL);
- const [secret, setSecret] = useState(apiConfig.secret);
+function APIConfig({ dispatch }) {
+ const [baseURL, setBaseURL] = useState('');
+ const [secret, setSecret] = useState('');
const [errMsg, setErrMsg] = useState('');
const userTouchedFlagRef = useRef(false);
@@ -47,14 +48,21 @@ function APIConfig({ apiConfig, dispatch }) {
if (ret[0] !== Ok) {
setErrMsg(ret[1]);
} else {
- dispatch(updateClashAPIConfig({ baseURL, secret }));
+ dispatch(addClashAPIConfig({ baseURL, secret }));
}
});
}, [baseURL, secret, dispatch]);
const handleContentOnKeyDown = useCallback(
- (e) => {
+ (e: React.KeyboardEvent<HTMLInputElement>) => {
+ if (
+ e.target instanceof Element &&
+ (!e.target.tagName || e.target.tagName.toUpperCase() !== 'INPUT')
+ ) {
+ return;
+ }
if (e.key !== 'Enter') return;
+
onConfirm();
},
[onConfirm]
@@ -90,8 +98,10 @@ function APIConfig({ apiConfig, dispatch }) {
</div>
<div className={s0.error}>{errMsg ? errMsg : null}</div>
<div className={s0.footer}>
- <Button label="Confirm" onClick={onConfirm} />
+ <Button label="Add" onClick={onConfirm} />
</div>
+ <div style={{ height: 20 }} />
+ <BackendList />
</div>
);
}
diff --git a/src/components/APIDiscovery.module.css b/src/components/APIDiscovery.module.css
index f2aaf71..6c1295a 100644
--- a/src/components/APIDiscovery.module.css
+++ b/src/components/APIDiscovery.module.css
@@ -12,11 +12,11 @@
display: flex;
justify-content: center;
+ overflow-y: auto;
}
.container {
position: relative;
- top: 10%;
margin-left: 20px;
margin-right: 20px;
}
diff --git a/src/components/BackendList.module.css b/src/components/BackendList.module.css
new file mode 100644
index 0000000..1de1972
--- /dev/null
+++ b/src/components/BackendList.module.css
@@ -0,0 +1,99 @@
+.ul {
+ position: relative;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ line-height: 1.8;
+
+ --width-max-content: 230px;
+}
+
+.li {
+ position: relative;
+ margin: 5px 0;
+ padding: 10px 0;
+ border-radius: 10px;
+ display: grid;
+ place-content: center;
+ grid-template-columns: 40px 1fr 40px;
+ grid-template-rows: 30px;
+ grid-template-areas: 'close url .';
+ column-gap: 10px;
+}
+
+.li:hover {
+ background-color: var(--bg-near-transparent);
+}
+
+.close {
+ opacity: 0;
+ grid-area: close;
+ place-self: center;
+}
+
+.li:hover .close,
+.li:hover .eye {
+ opacity: 1;
+}
+.close:focus,
+.eye:focus {
+ opacity: 1;
+}
+
+.hasSecret {
+ grid-template-rows: repeat(2, 30px);
+ grid-template-areas:
+ 'close url .'
+ 'close secret eye';
+}
+
+.url {
+ grid-area: url;
+}
+.secret {
+ grid-area: secret;
+}
+.eye {
+ grid-area: eye;
+ opacity: 0;
+ place-self: center;
+ cursor: pointer;
+}
+
+.url,
+.secret {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.btn {
+ outline: none;
+ appearance: none;
+ border: 1px solid transparent;
+ background-color: transparent;
+ color: inherit;
+ display: flex;
+ align-items: center;
+ padding: 5px;
+ border-radius: 100px;
+}
+.btn:focus {
+ border-color: var(--color-focus-blue);
+}
+.btn:hover:enabled {
+ background-color: var(--color-focus-blue);
+}
+.btn:active:enabled {
+ transform: scale(0.97);
+}
+.btn:disabled {
+ color: var(--color-text-secondary);
+}
+
+.url {
+ cursor: pointer;
+}
+.url:hover {
+ color: var(--color-text-highlight);
+}
diff --git a/src/components/BackendList.tsx b/src/components/BackendList.tsx
new file mode 100644
index 0000000..a0c993f
--- /dev/null
+++ b/src/components/BackendList.tsx
@@ -0,0 +1,147 @@
+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 { ClashAPIConfig } from 'src/types';
+
+import s from './BackendList.module.css';
+import { connect, useStoreActions } from './StateProvider';
+
+type Config = ClashAPIConfig & { addedAt: number };
+
+const mapState = (s) => ({
+ apiConfigs: getClashAPIConfigs(s),
+ selectedClashAPIConfigIndex: getSelectedClashAPIConfigIndex(s),
+});
+
+export const BackendList = connect(mapState)(BackendListImpl);
+
+function BackendListImpl({
+ apiConfigs,
+ selectedClashAPIConfigIndex,
+}: {
+ apiConfigs: Config[];
+ selectedClashAPIConfigIndex: number;
+}) {
+ const {
+ app: { removeClashAPIConfig, selectClashAPIConfig },
+ } = useStoreActions();
+
+ const onRemove = React.useCallback(
+ (conf: ClashAPIConfig) => {
+ removeClashAPIConfig(conf);
+ },
+ [removeClashAPIConfig]
+ );
+ const onSelect = React.useCallback(
+ (conf: ClashAPIConfig) => {
+ selectClashAPIConfig(conf);
+ },
+ [selectClashAPIConfig]
+ );
+
+ return (
+ <>
+ <ul className={s.ul}>
+ {apiConfigs.map((item, idx) => {
+ return (
+ <li
+ className={cx(s.li, {
+ [s.hasSecret]: item.secret,
+ [s.isSelected]: idx === selectedClashAPIConfigIndex,
+ })}
+ key={item.baseURL + item.secret}
+ >
+ <Item
+ disableRemove={idx === selectedClashAPIConfigIndex}
+ baseURL={item.baseURL}
+ secret={item.secret}
+ onRemove={onRemove}
+ onSelect={onSelect}
+ />
+ </li>
+ );
+ })}
+ </ul>
+ </>
+ );
+}
+
+function Item({
+ baseURL,
+ secret,
+ disableRemove,
+ onRemove,
+ onSelect,
+}: {
+ baseURL: string;
+ secret: string;
+ disableRemove: boolean;
+ onRemove: (x: ClashAPIConfig) => void;
+ onSelect: (x: ClashAPIConfig) => void;
+}) {
+ const [show, toggle] = useToggle();
+ const Icon = show ? EyeOff : Eye;
+
+ const handleTap = React.useCallback((e: React.KeyboardEvent) => {
+ e.stopPropagation();
+ }, []);
+
+ return (
+ <>
+ <Button
+ disabled={disableRemove}
+ onClick={() => onRemove({ baseURL, secret })}
+ className={s.close}
+ >
+ <Close size={20} />
+ </Button>
+ <span
+ className={s.url}
+ tabIndex={0}
+ role="button"
+ onClick={() => onSelect({ baseURL, secret })}
+ onKeyUp={handleTap}
+ >
+ {baseURL}
+ </span>
+ <span />
+ {secret ? (
+ <>
+ <span className={s.secret}>{show ? secret : '***'}</span>
+
+ <Button onClick={toggle} className={s.eye}>
+ <Icon size={20} />
+ </Button>
+ </>
+ ) : null}
+ </>
+ );
+}
+
+function Button({
+ children,
+ onClick,
+ className,
+ disabled,
+}: {
+ children: React.ReactNode;
+
+ onClick?: (e: React.MouseEvent<HTMLButtonElement>) => unknown;
+ className: string;
+ disabled?: boolean;
+}) {
+ return (
+ <button
+ disabled={disabled}
+ className={cx(className, s.btn)}
+ onClick={onClick}
+ >
+ {children}
+ </button>
+ );
+}
diff --git a/src/components/Config.js b/src/components/Config.js
index d5850d1..f14f7d9 100644
--- a/src/components/Config.js
+++ b/src/components/Config.js
@@ -2,12 +2,12 @@ import PropTypes from 'prop-types';
import React from 'react';
import {
- clearStorage,
getClashAPIConfig,
getLatencyTestUrl,
getSelectedChartStyleIndex,
} from '../store/app';
import { fetchConfigs, getConfigs, updateConfigs } from '../store/configs';
+import { openModal } from '../store/modals';
import Button from './Button';
import s0 from './Config.module.css';
import ContentHeader from './ContentHeader';
@@ -104,6 +104,10 @@ function ConfigImpl({
refConfigs.current = configs;
}, [configs]);
+ const openAPIConfigModal = useCallback(() => {
+ dispatch(openModal('apiConfig'));
+ }, [dispatch]);
+
const setConfigState = useCallback(
(name, val) => {
setConfigStateInternal({
@@ -256,7 +260,7 @@ function ConfigImpl({
</div>
<div>
<div className={s0.label}>Action</div>
- <Button label="Log out" onClick={clearStorage} />
+ <Button label="Switch backend" onClick={openAPIConfigModal} />
</div>
</div>
</div>
diff --git a/src/components/ErrorBoundary.js b/src/components/ErrorBoundary.js
index cc3898e..ff49e1e 100644
--- a/src/components/ErrorBoundary.js
+++ b/src/components/ErrorBoundary.js
@@ -1,13 +1,10 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
+// import { getSentry } from '../misc/sentry';
import { deriveMessageFromError } from '../misc/errors';
-import { getSentry } from '../misc/sentry';
import ErrorBoundaryFallback from './ErrorBoundaryFallback';
-// XXX this is no Hook equivalents for componentDidCatch
-// we have to use class for now
-
class ErrorBoundary extends Component {
static propTypes = {
children: PropTypes.node,
@@ -15,44 +12,13 @@ class ErrorBoundary extends Component {
state = { error: null };
- loadSentry = async () => {
- if (this.sentry) return this.sentry;
- const x = await getSentry();
- this.sentry = x;
- return this.sentry;
- };
-
- // static getDerivedStateFromError(error) {
- // return { error };
- // }
-
- componentDidMount() {
- // this.loadSentry();
+ static getDerivedStateFromError(error) {
+ return { error };
}
- componentDidCatch(error, _info) {
- this.setState({ error });
- // eslint-disable-next-line no-console
- // console.log(error, errorInfo);
- // this.setState({ error });
- // this.loadSentry().then(Sentry => {
- // Sentry.withScope(scope => {
- // Object.keys(errorInfo).forEach(key => {
- // scope.setExtra(key, errorInfo[key]);
- // });
- // Sentry.captureException(error);
- // });
- // });
- }
-
- showReportDialog = () => {
- this.loadSentry().then((Sentry) => Sentry.showReportDialog());
- };
-
render() {
if (this.state.error) {
const { message, detail } = deriveMessageFromError(this.state.error);
- //render fallback UI
return <ErrorBoundaryFallback message={message} detail={detail} />;
} else {
return this.props.children;
diff --git a/src/components/Root.js b/src/components/Root.js
index 6c13163..8c06100 100644
--- a/src/components/Root.js
+++ b/src/components/Root.js
@@ -1,11 +1,12 @@
import './Root.css';
import React, { lazy, Suspense } from 'react';
-import { HashRouter as Router, Route, Routes } from 'react-router-dom';
+import { HashRouter as Router, useRoutes } from 'react-router-dom';
import { RecoilRoot } from 'recoil';
import { About } from 'src/components/about/About';
import { actions, initialState } from '../store';
+import APIConfig from './APIConfig';
import APIDiscovery from './APIDiscovery';
import ErrorBoundary from './ErrorBoundary';
import Home from './Home';
@@ -52,33 +53,50 @@ const Rules = lazy(() =>
);
const routes = [
- ['home', '/', <Home />],
- ['connections', '/connections', <Connections />],
- ['configs', '/configs', <Config />],
- ['logs', '/logs', <Logs />],
- ['proxies', '/proxies', <Proxies />],
- ['rules', '/rules', <Rules />],
- ['about', '/about', <About />],
- __DEV__ ? ['style', '/style', <StyleGuide />] : false,
+ { path: '/', element: <Home /> },
+ { path: '/connections', element: <Connections /> },
+ { path: '/configs', element: <Config /> },
+ { path: '/logs', element: <Logs /> },
+ { path: '/proxies', element: <Proxies /> },
+ { path: '/rules', element: <Rules /> },
+ { path: '/about', element: <About /> },
+ __DEV__ ? { path: '/style', element: <StyleGuide /> } : false,
].filter(Boolean);
+function RouteInnerApp() {
+ return useRoutes(routes);
+}
+
+function SideBarApp() {
+ return (
+ <>
+ <APIDiscovery />
+ <SideBar />
+ <div className={s0.content}>
+ <Suspense fallback={<Loading2 />}>
+ <RouteInnerApp />
+ </Suspense>
+ </div>
+ </>
+ );
+}
+
+function App() {
+ return useRoutes([
+ { path: '/backend', element: <APIConfig /> },
+ { path: '*', element: <SideBarApp /> },
+ ]);
+}
+
const Root = () => (
<ErrorBoundary>
<RecoilRoot>
<StateProvider initialState={initialState} actions={actions}>
<Router>
<div className={s0.app}>
- <APIDiscovery />
- <SideBar />
- <div className={s0.content}>
- <Suspense fallback={<Loading2 />}>
- <Routes>
- {routes.map(([key, path, element]) => (
- <Route key={key} path={path} element={element} />
- ))}
- </Routes>
- </Suspense>
- </div>
+ <Suspense fallback={<Loading2 />}>
+ <App />
+ </Suspense>
</div>
</Router>
</StateProvider>
diff --git a/src/components/TrafficChart.js b/src/components/TrafficChart.js
index 18bda77..bcfd4dc 100644
--- a/src/components/TrafficChart.js
+++ b/src/components/TrafficChart.js
@@ -25,8 +25,7 @@ export default connect(mapState)(TrafficChart);
function TrafficChart({ apiConfig, selectedChartStyleIndex }) {
const Chart = chartJSResource.read();
- const { hostname, port, secret } = apiConfig;
- const traffic = fetchData({ hostname, port, secret });
+ const traffic = fetchData(apiConfig);
const data = useMemo(
() => ({
labels: traffic.labels,
diff --git a/src/store/app.js b/src/store/app.js
index dc0e269..84ef96b 100644
--- a/src/store/app.js
+++ b/src/store/app.js
@@ -1,4 +1,4 @@
-import { clearState, loadState, saveState } from '../misc/storage';
+import { loadState, saveState } from '../misc/storage';
import { debounce, trimTrailingSlash } from '../misc/utils';
import { fetchConfigs } from './configs';
import { closeModal } from './modals';
@@ -7,6 +7,9 @@ export const getClashAPIConfig = (s) => {
const idx = s.app.selectedClashAPIConfigIndex;
return s.app.clashAPIConfigs[idx];
};
+export const getSelectedClashAPIConfigIndex = (s) =>
+ s.app.selectedClashAPIConfigIndex;
+export const getClashAPIConfigs = (s) => s.app.clashAPIConfigs;
export const getTheme = (s) => s.app.theme;
export const getSelectedChartStyleIndex = (s) => s.app.selectedChartStyleIndex;
export const getLatencyTestUrl = (s) => s.app.latencyTestUrl;
@@ -17,6 +20,66 @@ export const getAutoCloseOldConns = (s) => s.app.autoCloseOldConns;
const saveStateDebounced = debounce(saveState, 600);
+function findClashAPIConfigIndex(getState, { baseURL, secret }) {
+ const arr = getClashAPIConfigs(getState());
+ for (let i = 0; i < arr.length; i++) {
+ const x = arr[i];
+ if (x.baseURL === baseURL && x.secret === secret) return i;
+ }
+}
+
+export function addClashAPIConfig({ baseURL, secret }) {
+ return async (dispatch, getState) => {
+ const idx = findClashAPIConfigIndex(getState, { baseURL, secret });
+ // already exists
+ if (idx) return;
+
+ const clashAPIConfig = { baseURL, secret, addedAt: Date.now() };
+ dispatch('addClashAPIConfig', (s) => {
+ s.app.clashAPIConfigs.push(clashAPIConfig);
+ });
+ // side effect
+ saveState(getState().app);
+ };
+}
+
+export function removeClashAPIConfig({ baseURL, secret }) {
+ return async (dispatch, getState) => {
+ const idx = findClashAPIConfigIndex(getState, { baseURL, secret });
+ dispatch('removeClashAPIConfig', (s) => {
+ s.app.clashAPIConfigs = [
+ ...s.app.clashAPIConfigs.slice(0, idx),
+ ...s.app.clashAPIConfigs.slice(idx + 1),
+ ];
+ });
+ // side effect
+ saveState(getState().app);
+ };
+}
+
+export function selectClashAPIConfig({ baseURL, secret }) {
+ return async (dispatch, getState) => {
+ const idx = findClashAPIConfigIndex(getState, { baseURL, secret });
+ const curr = getSelectedClashAPIConfigIndex(getState());
+ if (curr !== idx) {
+ dispatch('selectClashAPIConfig', (s) => {
+ s.app.selectedClashAPIConfigIndex = idx;
+ });
+ }
+ // side effect
+ saveState(getState().app);
+
+ // manual clean up is too complex
+ // we just reload the app
+ try {
+ window.location.reload();
+ } catch (err) {
+ // ignore
+ }
+ };
+}
+
+// unused
export function updateClashAPIConfig({ baseURL, secret }) {
return async (dispatch, getState) => {
const clashAPIConfig = { baseURL, secret };
@@ -55,15 +118,6 @@ export function switchTheme() {
};
}
-export function clearStorage() {
- clearState();
- try {
- window.location.reload();
- } catch (err) {
- // ignore
- }
-}
-
export function selectChartStyleIndex(selectedChartStyleIndex) {
return (dispatch, getState) => {
dispatch('appSelectChartStyleIndex', (s) => {
@@ -97,6 +151,7 @@ export function updateCollapsibleIsOpen(prefix, name, v) {
const defaultClashAPIConfig = {
baseURL: 'http://127.0.0.1:7892',
secret: '',
+ addedAt: 0,
};
// type Theme = 'light' | 'dark';
const defaultState = {
@@ -133,25 +188,24 @@ export function initialState() {
const query = parseConfigQueryString();
const conf = s.clashAPIConfigs[s.selectedClashAPIConfigIndex];
- const url = new URL(conf.baseURL);
- if (query.hostname) {
- url.hostname = query.hostname;
- }
- if (query.port) {
- url.port = query.port;
- }
- // url.href is a stringifier and it appends a trailing slash
- // that is not we want
- conf.baseURL = trimTrailingSlash(url.href);
-
- if (query.secret) {
- conf.secret = query.secret;
+ if (conf) {
+ const url = new URL(conf.baseURL);
+ if (query.hostname) {
+ url.hostname = query.hostname;
+ }
+ if (query.port) {
+ url.port = query.port;
+ }
+ // url.href is a stringifier and it appends a trailing slash
+ // that is not we want
+ conf.baseURL = trimTrailingSlash(url.href);
+ if (query.secret) {
+ conf.secret = query.secret;
+ }
}
- if (query.theme) {
- if (query.theme === 'dark' || query.theme === 'light') {
- s.theme = query.theme;
- }
+ if (query.theme === 'dark' || query.theme === 'light') {
+ s.theme = query.theme;
}
// set initial theme
setTheme(s.theme);
diff --git a/src/store/configs.js b/src/store/configs.js
index f114cef..bcd4ac8 100644
--- a/src/store/configs.js
+++ b/src/store/configs.js
@@ -2,8 +2,8 @@ import * as configsAPI from '../api/configs';
import * as trafficAPI from '../api/traffic';
import { openModal } from './modals';
-export const getConfigs = s => s.configs.configs;
-export const getLogLevel = s => s.configs.configs['log-level'];
+export const getConfigs = (s) => s.configs.configs;
+export const getLogLevel = (s) => s.configs.configs['log-level'];
export function fetchConfigs(apiConfig) {
return async (dispatch, getState) => {
@@ -11,25 +11,20 @@ export function fetchConfigs(apiConfig) {
try {
res = await configsAPI.fetchConfigs(apiConfig);
} catch (err) {
- // eslint-disable-next-line no-console
- console.log('Error fetch configs', err);
+ // TypeError and AbortError
dispatch(openModal('apiConfig'));
return;
}
if (!res.ok) {
- if (res.status === 404 || res.status === 401) {
- dispatch(openModal('apiConfig'));
- } else {
- // eslint-disable-next-line no-console
- console.log('Error fetch configs', res.statusText);
- }
+ console.log('Error fetch configs', res.statusText);
+ dispatch(openModal('apiConfig'));
return;
}
const payload = await res.json();
- dispatch('store/configs#fetchConfigs', s => {
+ dispatch('store/configs#fetchConfigs', (s) => {
s.configs.configs = payload;
});
@@ -47,25 +42,25 @@ export function fetchConfigs(apiConfig) {
}
function markHaveFetchedConfig() {
- return dispatch => {
- dispatch('store/configs#markHaveFetchedConfig', s => {
+ return (dispatch) => {
+ dispatch('store/configs#markHaveFetchedConfig', (s) => {
s.configs.haveFetchedConfig = true;
});
};
}
export function updateConfigs(apiConfig, partialConfg) {
- return async dispatch => {
+ return async (dispatch) => {
configsAPI
.updateConfigs(apiConfig, partialConfg)
.then(
- res => {
+ (res) => {
if (res.ok === false) {
// eslint-disable-next-line no-console
console.log('Error update configs', res.statusText);
}
},
- err => {
+ (err) => {
// eslint-disable-next-line no-console
console.log('Error update configs', err);
throw err;
@@ -75,7 +70,7 @@ export function updateConfigs(apiConfig, partialConfg) {
dispatch(fetchConfigs(apiConfig));
});
- dispatch('storeConfigsOptimisticUpdateConfigs', s => {
+ dispatch('storeConfigsOptimisticUpdateConfigs', (s) => {
s.configs.configs = { ...s.configs.configs, ...partialConfg };
});
};
@@ -88,7 +83,7 @@ export const initialState = {
'redir-port': 0,
'allow-lan': false,
mode: 'Rule',
- 'log-level': 'info'
+ 'log-level': 'info',
},
- haveFetchedConfig: false
+ haveFetchedConfig: false,
};
diff --git a/src/store/index.js b/src/store/index.js
index bd4e7a9..4fc8e4c 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,6 +1,8 @@
import {
initialState as app,
+ removeClashAPIConfig,
selectChartStyleIndex,
+ selectClashAPIConfig,
updateAppConfig,
updateCollapsibleIsOpen,
} from './app';
@@ -24,6 +26,8 @@ export const actions = {
app: {
updateCollapsibleIsOpen,
updateAppConfig,
+ removeClashAPIConfig,
+ selectClashAPIConfig,
},
proxies: proxiesActions,
};
diff --git a/yarn.lock b/yarn.lock
index f747e9b..0150869 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1021,7 +1021,7 @@
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.11.2", "@babel/runtime@^7.8.4":
+"@babel/runtime@^7.11.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
@@ -1218,56 +1218,56 @@
schema-utils "^2.6.5"
source-map "^0.7.3"
-"@sentry/browser@^5.22.3":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.22.3.tgz#7a64bd1cf01bf393741a3e4bf35f82aa927f5b4e"
- integrity sha512-2TzE/CoBa5ZkvxJizDdi1Iz1ldmXSJpFQ1mL07PIXBjCt0Wxf+WOuFSj5IP4L40XHfJE5gU8wEvSH0VDR8nXtA==
+"@sentry/browser@^5.23.0":
+ version "5.23.0"
+ resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.23.0.tgz#fc3a7a435a4524aa949f91d442435efda153fc0a"
+ integrity sha512-lBBHb/NFDOy1K5E/noDkgaibTtxp8F8gmAaVhhpGvOjlcBp1wzNJhWRePYKWgjJ7yFudxGi4Qbferdhm9RwzbA==
dependencies:
- "@sentry/core" "5.22.3"
- "@sentry/types" "5.22.3"
- "@sentry/utils" "5.22.3"
+ "@sentry/core" "5.23.0"
+ "@sentry/types" "5.23.0"
+ "@sentry/utils" "5.23.0"
tslib "^1.9.3"
-"@sentry/[email protected]":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.22.3.tgz#030f435f2b518f282ba8bd954dac90cd70888bd7"
- integrity sha512-eGL5uUarw3o4i9QUb9JoFHnhriPpWCaqeaIBB06HUpdcvhrjoowcKZj1+WPec5lFg5XusE35vez7z/FPzmJUDw==
+"@sentry/[email protected]":
+ version "5.23.0"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.23.0.tgz#4d12ee4f5593e66fa5ffde0f9e9164a5468e5cec"
+ integrity sha512-K8Wp/g1opaauKJh2w5Z1Vw/YdudHQgH6Ng5fBazHZxA7zB9R8EbVKDsjy8XEcyHsWB7fTSlYX/7coqmZNOADdg==
dependencies:
- "@sentry/hub" "5.22.3"
- "@sentry/minimal" "5.22.3"
- "@sentry/types" "5.22.3"
- "@sentry/utils" "5.22.3"
+ "@sentry/hub" "5.23.0"
+ "@sentry/minimal" "5.23.0"
+ "@sentry/types" "5.23.0"
+ "@sentry/utils" "5.23.0"
tslib "^1.9.3"
-"@sentry/[email protected]":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.22.3.tgz#08309a70d2ea8d5e313d05840c1711f34f2fffe5"
- integrity sha512-INo47m6N5HFEs/7GMP9cqxOIt7rmRxdERunA3H2L37owjcr77MwHVeeJ9yawRS6FMtbWXplgWTyTIWIYOuqVbw==
+"@sentry/[email protected]":
+ version "5.23.0"
+ resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.23.0.tgz#7350c2971fafdb9f883f0629fd1b35d2288cd6e1"
+ integrity sha512-P0sevLI9qAQc1J+AcHzNXwj83aG3GKiABVQJp0rgCUMtrXqLawa+j8pOHg8p7QWroHM7TKDMKeny9WemXBgzBQ==
dependencies:
- "@sentry/types" "5.22.3"
- "@sentry/utils" "5.22.3"
+ "@sentry/types" "5.23.0"
+ "@sentry/utils" "5.23.0"
tslib "^1.9.3"
-"@sentry/[email protected]":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.22.3.tgz#706e4029ae5494123d3875c658ba8911aa5cc440"
- integrity sha512-HoINpYnVYCpNjn2XIPIlqH5o4BAITpTljXjtAftOx6Hzj+Opjg8tR8PWliyKDvkXPpc4kXK9D6TpEDw8MO0wZA==
+"@sentry/[email protected]":
+ version "5.23.0"
+ resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.23.0.tgz#93df781a98f0b334425f68b1fa0f4e1a86d8fa45"
+ integrity sha512-/w/B7ShMVu/tLI0/A5X+w6GfdZIQdFQihWyIK1vXaYS5NS6biGI3K6DcACuMrD/h4BsqlfgdXSOHHrmCJcyCXQ==
dependencies:
- "@sentry/hub" "5.22.3"
- "@sentry/types" "5.22.3"
+ "@sentry/hub" "5.23.0"
+ "@sentry/types" "5.23.0"
tslib "^1.9.3"
-"@sentry/[email protected]":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.22.3.tgz#d1d547b30ee8bd7771fa893af74c4f3d71f0fd18"
- integrity sha512-cv+VWK0YFgCVDvD1/HrrBWOWYG3MLuCUJRBTkV/Opdy7nkdNjhCAJQrEyMM9zX0sac8FKWKOHT0sykNh8KgmYw==
+"@sentry/[email protected]":
+ version "5.23.0"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.23.0.tgz#935701637c2d5b1c123ac292bc253bddf451b076"
+ integrity sha512-PbN5MVWxrq05sZ707lc8lleV0xSsI6jWr9h9snvbAuMjcauE0lmdWmjoWKY3PAz2s1mGYFh55kIo8SmQuVwbYg==
-"@sentry/[email protected]":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.22.3.tgz#e3bda3e789239eb16d436f768daa12829f33d18f"
- integrity sha512-AHNryXMBvIkIE+GQxTlmhBXD0Ksh+5w1SwM5qi6AttH+1qjWLvV6WB4+4pvVvEoS8t5F+WaVUZPQLmCCWp6zKw==
+"@sentry/[email protected]":
+ version "5.23.0"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.23.0.tgz#5e15f684b5a8f9c86e4ba15d81101eac7d6c240b"
+ integrity sha512-D5gQDM0wEjKxhE+YNvCuCHo/6JuaORF2/3aOhoJBR+dy9EACRspg7kp3+9KF44xd2HVEXkSVCJkv8/+sHePYRQ==
dependencies:
- "@sentry/types" "5.22.3"
+ "@sentry/types" "5.23.0"
tslib "^1.9.3"
"@types/anymatch@*":
@@ -3665,7 +3665,7 @@ eslint-module-utils@^2.6.0:
debug "^2.6.9"
pkg-dir "^2.0.0"
-eslint-plugin-flowtype@^5.1.0:
+eslint-plugin-flowtype@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.2.0.tgz#a4bef5dc18f9b2bdb41569a4ab05d73805a3d261"
integrity sha512-z7ULdTxuhlRJcEe1MVljePXricuPOrsWfScRXFhNzVD5dmTHWjIF57AxD0e7AbEoLSbjSsaA5S+hCg43WvpXJQ==
@@ -3692,10 +3692,10 @@ eslint-plugin-import@^2.22.0:
resolve "^1.17.0"
tsconfig-paths "^3.9.0"
-eslint-plugin-jest@^24.0.0:
- version "24.0.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.0.0.tgz#6b1c460c529104c7d16d889e76fe708b281c4d14"
- integrity sha512-a0G7hSDbuBCW4PNT6MVpAyfnGbUDOqxzOyhR6wT2BIBnR7MhvfAqd6KKfsTjX+Z3gxzIHiEsihzdClU4cSc6qQ==
+eslint-plugin-jest@^24.0.1:
+ version "24.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.0.1.tgz#ad5e091d47cf895e15dc115e18f98471135a334f"
+ integrity sha512-8tYFDqOHGr7vVfdVYspmlV4sRBTylrM4gSLgkGKlO6F+djDOEJ+tEU7I50smUs7AIvFnNZutXUQAMgI9s9N6xQ==
dependencies:
"@typescript-eslint/experimental-utils" "^4.0.1"
@@ -3716,10 +3716,10 @@ eslint-plugin-jsx-a11y@^6.3.1:
jsx-ast-utils "^2.4.1"
language-tags "^1.0.5"
-eslint-plugin-react-hooks@^4.0.8:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.1.0.tgz#6323fbd5e650e84b2987ba76370523a60f4e7925"
- integrity sha512-36zilUcDwDReiORXmcmTc6rRumu9JIM3WjSvV0nclHoUQ0CNrX866EwONvLR/UqaeqFutbAnVu8PEmctdo2SRQ==
+eslint-plugin-react-hooks@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.1.2.tgz#2eb53731d11c95826ef7a7272303eabb5c9a271e"
+ integrity sha512-ykUeqkGyUGgwTtk78C0o8UG2fzwmgJ0qxBGPp2WqRKsTwcLuVf01kTDRAtOsd4u6whX2XOC8749n2vPydP82fg==
eslint-plugin-react@^7.20.6:
version "7.20.6"
@@ -3781,10 +3781,10 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
-eslint@^7.6.0:
- version "7.8.1"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.8.1.tgz#e59de3573fb6a5be8ff526c791571646d124a8fa"
- integrity sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==
+eslint@^7.9.0:
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.9.0.tgz#522aeccc5c3a19017cf0cb46ebfd660a79acf337"
+ integrity sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==
dependencies:
"@babel/code-frame" "^7.0.0"
"@eslint/eslintrc" "^0.1.3"
@@ -4243,10 +4243,10 @@ [email protected]:
tapable "^1.0.0"
worker-rpc "^0.1.0"
-fork-ts-checker-webpack-plugin@^5.0.14:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.1.0.tgz#586fbee24aeea950c53bab529e32017f543e71cf"
- integrity sha512-vuKyEjSLGbhQbEr5bifXXOkr9iV73L6n72mHoHIv7okvrf7O7z6RKeplM6C6ATPsukoQivij+Ba1vcptL60Z2g==
+fork-ts-checker-webpack-plugin@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.0.tgz#780a14fb0da02a892baedd7aa0d089a1eda7b3e5"
+ integrity sha512-NEKcI0+osT5bBFZ1SFGzJMQETjQWZrSvMO1g0nAR/w0t328Z41eN8BJEIZyFCl2HsuiJpa9AN474Nh2qLVwGLQ==
dependencies:
"@babel/code-frame" "^7.8.3"
"@types/json-schema" "^7.0.5"
@@ -4272,14 +4272,14 @@ fragment-cache@^0.2.1:
dependencies:
map-cache "^0.2.2"
-framer-motion@^2.6.7:
- version "2.6.7"
- resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-2.6.7.tgz#f01685750573ab24fec8b53ac48a05e8fec6deef"
- integrity sha512-szwqKCH/yvMtaFmtphP3np/1/5HMDbPWfmAbVMXDvofC3qDi4+XsxVnI60egCnmYGxPeE5t4JFbZjAqOZy4HPg==
+framer-motion@^2.6.13:
+ version "2.6.13"
+ resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-2.6.13.tgz#cc26faf53bffb2d9a558bc71a3adaf3c437c0e55"
+ integrity sha512-ScEdiDyAT+kH51axqxFcHA9RLnJ8TpMQBf8HwcXBOt6wDVptHdewEnE3T7semz+7OY0sj0RCsUDhQaWo78aMqQ==
dependencies:
framesync "^4.1.0"
hey-listen "^1.0.8"
- popmotion "9.0.0-rc.13"
+ popmotion "9.0.0-rc.14"
style-value-types "^3.1.9"
tslib "^1.10.0"
optionalDependencies:
@@ -4829,10 +4829,10 @@ [email protected]:
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
-immer@^7.0.8:
- version "7.0.8"
- resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.8.tgz#41dcbc5669a76500d017bef3ad0d03ce0a1d7c1e"
- integrity sha512-XnpIN8PXBBaOD43U8Z17qg6RQiKQYGDGGCIbz1ixmLGwBkSWwmrmx5X7d+hTtXDM8ur7m5OdLE0PiO+y5RB3pw==
+immer@^7.0.9:
+ version "7.0.9"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.9.tgz#28e7552c21d39dd76feccd2b800b7bc86ee4a62e"
+ integrity sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A==
import-fresh@^2.0.0:
version "2.0.0"
@@ -5760,10 +5760,10 @@ mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-mini-css-extract-plugin@^0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.0.tgz#3918953075109d4ca204bf1e8a393a78d3cc821f"
- integrity sha512-dVWGuWJlQw2lZxsxBI3hOsoxg1k3DruLR0foHQLSkQMfk+qLJbv9dUk8fjmjWQKN9ef2n54ehA2FjClAsQhrWQ==
+mini-css-extract-plugin@^0.11.2:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.2.tgz#e3af4d5e04fbcaaf11838ab230510073060b37bf"
+ integrity sha512-h2LknfX4U1kScXxH8xE9LCOqT5B+068EAj36qicMb8l4dqdJoyHcmWmpd+ueyZfgu/POvIn+teoUnTtei2ikug==
dependencies:
loader-utils "^1.1.0"
normalize-url "1.9.1"
@@ -6554,10 +6554,10 @@ please-upgrade-node@^3.2.0:
dependencies:
semver-compare "^1.0.0"
- version "9.0.0-rc.13"
- resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.0-rc.13.tgz#0280968fb0dc3bd273cc3dbd4da24b01b6cfbcce"
- integrity sha512-M8Ksx2THYrAUrptE5Ydd3jazQAMoXxqpClR/K8xK87v4UrJUTCb39kNar/ucJ4Rs7qPqPdVu+iqPKOJhpMylXQ==
+ version "9.0.0-rc.14"
+ resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.0-rc.14.tgz#e57351b7b85a3e42b7a16affbbd440138797c11f"
+ integrity sha512-zdMw1OSKjFBH+KKpZx7P+cGSUb3QCqg5QD12f6llucUeEFT+SDZYxvTY09JI23ZcJyzxgKFT1anbLq0eZ9bj3g==
dependencies:
framesync "^4.1.0"
hey-listen "^1.0.8"
@@ -6652,10 +6652,10 @@ postcss-import@^12.0.1:
read-cache "^1.0.0"
resolve "^1.1.7"
-postcss-loader@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.0.0.tgz#bfd04521d2a2db69cb9e8a7cee0a5ae704e751dc"
- integrity sha512-LdpfM9yCVFeJzofnaFvLf3g9oMuH2mIIqOcu81n6JHxzRNBl78GHiYWUJ5gf4c7A7VZiBCeWwfVAMw/mQCAM3Q==
+postcss-loader@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.0.1.tgz#d1a2cf443005bcd65e856d3881204886646398d4"
+ integrity sha512-m+2fe21cs/1Oz4Yds90al5uqVSc0yJRhYSfCRnsnVLt3z0QoNPpqLdgW7CGVWmlUlKEGL9vmq+P4hHS6Orb5DA==
dependencies:
cosmiconfig "^7.0.0"
klona "^2.0.3"
@@ -7239,10 +7239,12 @@ react-modal@^3.11.1:
react-lifecycles-compat "^3.0.0"
warning "^4.0.3"
-react-query@^2.15.4:
- version "2.15.4"
- resolved "https://registry.yarnpkg.com/react-query/-/react-query-2.15.4.tgz#0447510fc30aebba5a4b99879ec4b7155d9b3f20"
- integrity sha512-gEF2Ebe1MtiyLKEaVEIlRMl6rwvP/RVwP+Xf68vhXDfD91IeZkkW7plRjoaHa0/NeUPM1AgTHb1Z7NtqaYDXjA==
+react-query@^2.17.0:
+ version "2.17.0"
+ resolved "https://registry.yarnpkg.com/react-query/-/react-query-2.17.0.tgz#ac6c1a17398ab86c65008d7a9a4c0d5385626d10"
+ integrity sha512-YtJ6Oot1vHyAHmllPdINEc0+3NnkjIWUcXZBUiScf+MpcRbzn8zBTc+QLF8dta+Zfm/HPHz1fFMYjAmTOSc/zw==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
react-refresh@^0.8.2:
version "0.8.3"
@@ -8383,19 +8385,19 @@ terser-webpack-plugin@^1.4.3:
webpack-sources "^1.4.0"
worker-farm "^1.7.0"
-terser-webpack-plugin@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.1.0.tgz#6e9d6ae4e1a900d88ddce8da6a47507ea61f44bc"
- integrity sha512-0ZWDPIP8BtEDZdChbufcXUigOYk6dOX/P/X0hWxqDDcVAQLb8Yy/0FAaemSfax3PAA67+DJR778oz8qVbmy4hA==
+terser-webpack-plugin@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.0.tgz#6240a71101a55c6823d84e11c8fff380b9dfd26f"
+ integrity sha512-Wi0YFbWKG8gBXhbJmrMusRcoXl/C9U5BzIPC2Tn3Si0hejGhhIh0gPf9rEfOCxwigzRPLC8PXv42qDiRTocMXg==
dependencies:
cacache "^15.0.5"
find-cache-dir "^3.3.1"
jest-worker "^26.3.0"
p-limit "^3.0.2"
- schema-utils "^2.6.6"
+ schema-utils "^2.7.1"
serialize-javascript "^4.0.0"
source-map "^0.6.1"
- terser "^5.0.0"
+ terser "^5.3.0"
webpack-sources "^1.4.3"
terser@^4.1.2:
@@ -8416,10 +8418,10 @@ terser@^4.6.3:
source-map "~0.6.1"
source-map-support "~0.5.12"
-terser@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/terser/-/terser-5.0.0.tgz#269640e4e92f15d628de1e5f01c4c61e1ba3d765"
- integrity sha512-olH2DwGINoSuEpSGd+BsPuAQaA3OrHnHnFL/rDB2TVNc3srUbz/rq/j2BlF4zDXI+JqAvGr86bIm1R2cJgZ3FA==
+terser@^5.3.0:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.3.1.tgz#f50fe20ab48b15234fe9bdd86b10148ad5fca787"
+ integrity sha512-yD80f4hdwCWTH5mojzxe1q8bN1oJbsK/vfJGLcPZM/fl+/jItIVNKhFIHqqR71OipFWMLgj3Kc+GIp6CeIqfnA==
dependencies:
commander "^2.20.0"
source-map "~0.6.1"