Skip to content

Commit

Permalink
Refactor <Config >
Browse files Browse the repository at this point in the history
  • Loading branch information
haishanh committed Oct 4, 2023
1 parent f6d1110 commit 3232bf2
Show file tree
Hide file tree
Showing 15 changed files with 93 additions and 199 deletions.
25 changes: 19 additions & 6 deletions src/api/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ import { ClashAPIConfig } from 'src/types';

const endpoint = '/configs';

export async function fetchConfigs2(ctx: { queryKey: readonly [string, ClashAPIConfig] }) {
const endpoint = ctx.queryKey[0];
const apiConfig = ctx.queryKey[1];
const { url, init } = getURLAndInit(apiConfig);
const res = await fetch(url + endpoint, init);
if (!res.ok) {
throw new Error('TODO');
}
return await res.json();
}

export function updateConfigs(apiConfig: ClashAPIConfig) {
return async (o: Partial<ClashGeneralConfig>) => {
const { url, init } = getURLAndInit(apiConfig);
const body = JSON.stringify(configsPatchWorkaround(o));
return await fetch(url + endpoint, { ...init, body, method: 'PATCH' });
};
}

export async function fetchConfigs(apiConfig: ClashAPIConfig) {
const { url, init } = getURLAndInit(apiConfig);
return await fetch(url + endpoint, init);
Expand All @@ -21,9 +40,3 @@ function configsPatchWorkaround(o: ClashConfigPartial) {
}
return o;
}

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' });
}
1 change: 1 addition & 0 deletions src/api/traffic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ function pump(reader: ReadableStreamDefaultReader) {
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
let wsState: number;
function fetchData(apiConfig: ClashAPIConfig) {
// TODO if apiConfig changed, should we reset?
if (fetched || wsState === 1) return traffic;
wsState = 1;
const url = buildWebSocketURL(apiConfig, endpoint);
Expand Down
1 change: 1 addition & 0 deletions src/components/APIConfig.module.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.root {
margin: 0 auto;
&:focus {
outline: none;
}
Expand Down
18 changes: 2 additions & 16 deletions src/components/APIDiscovery.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
import * as React from 'react';
import { ThemeSwitcher } from 'src/components/shared/ThemeSwitcher';
import { DOES_NOT_SUPPORT_FETCH, errors, YacdError } from 'src/misc/errors';
import { fetchConfigs } from 'src/store/configs';
import { closeModal } from 'src/store/modals';
import { DispatchFn, State, StateModals } from 'src/store/types';

import { useApiConfig } from '$src/store/app';

import APIConfig from './APIConfig';
import s0 from './APIDiscovery.module.scss';
import Modal from './Modal';
import { connect } from './StateProvider';

const { useCallback, useEffect } = React;
const { useCallback } = React;

function APIDiscovery({
dispatch,
modals,
}: {
dispatch: DispatchFn;
modals: StateModals;
}) {
const apiConfig = useApiConfig();
function APIDiscovery({ dispatch, modals }: { dispatch: DispatchFn; modals: StateModals }) {
if (!window.fetch) {
const { detail } = errors[DOES_NOT_SUPPORT_FETCH];
const err = new YacdError(detail, DOES_NOT_SUPPORT_FETCH);
Expand All @@ -31,9 +21,6 @@ function APIDiscovery({
const closeApiConfigModal = useCallback(() => {
dispatch(closeModal('apiConfig'));
}, [dispatch]);
useEffect(() => {
dispatch(fetchConfigs(apiConfig));
}, [dispatch, apiConfig]);

return (
<Modal
Expand All @@ -57,7 +44,6 @@ function APIDiscovery({

const mapState = (s: State) => ({
modals: s.modals,
// apiConfig: getClashAPIConfig(s),
});

export default connect(mapState)(APIDiscovery);
3 changes: 1 addition & 2 deletions src/components/BackendList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function BackendList() {
const removeClashAPIConfig = React.useCallback(
(conf: ClashAPIConfig) => {
const idx = findClashAPIConfigIndex(apiConfigs, conf);
setApiConfigs(apiConfigs => {
setApiConfigs((apiConfigs) => {
apiConfigs.splice(idx, 1);
return [...apiConfigs];
});
Expand Down Expand Up @@ -49,7 +49,6 @@ export function BackendList() {
} catch (err) {
// ignore
}

},
[apiConfigs, selectedClashAPIConfigIndex, setSelectedClashAPIConfigIndex],
);
Expand Down
79 changes: 39 additions & 40 deletions src/components/Config.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useAtom } from 'jotai';
import * as React from 'react';
import { LogOut } from 'react-feather';
import { useTranslation } from 'react-i18next';
import * as logsApi from 'src/api/logs';
import Select from 'src/components/shared/Select';
import { ClashGeneralConfig, DispatchFn, State } from 'src/store/types';
import { redirect } from 'react-router';

import { updateConfigs } from '$src/api/configs';
import * as logsApi from '$src/api/logs';
import Select from '$src/components/shared/Select';
import {
darkModePureBlackToggleAtom,
latencyTestUrlAtom,
selectedChartStyleIndexAtom,
useApiConfig,
} from '../store/app';
import { fetchConfigs, getConfigs, updateConfigs } from '../store/configs';
import { openModal } from '../store/modals';
} from '$src/store/app';
import { useClashConfig } from '$src/store/configs';
import { ClashGeneralConfig } from '$src/store/types';

import Button from './Button';
import s0 from './Config.module.scss';
import ContentHeader from './ContentHeader';
import { ToggleInput } from './form/Toggle';
import Input, { SelfControlledInput } from './Input';
import { Selection2 } from './Selection';
import { connect } from './StateProvider';
import TrafficChartSample from './TrafficChartSample';

const { useEffect, useState, useCallback, useRef, useMemo } = React;
Expand Down Expand Up @@ -53,35 +55,20 @@ const modeOptions = [
['Direct', 'Direct'],
];

const mapState = (s: State) => ({
configs: getConfigs(s),
});

const Config = connect(mapState)(ConfigImpl);
export default connect(mapState)(ConfigContainer);

function ConfigContainer({
dispatch,
configs,
}: {
dispatch: DispatchFn;
configs: ClashGeneralConfig;
}) {
const apiConfig = useApiConfig();
useEffect(() => {
dispatch(fetchConfigs(apiConfig));
}, [dispatch, apiConfig]);
return <Config configs={configs} />;
export default function ConfigContainer() {
const { data } = useClashConfig();
return <Config configs={data} />;
}

type ConfigImplProps = {
dispatch: DispatchFn;
configs: ClashGeneralConfig;
};

function ConfigImpl({ dispatch, configs }: ConfigImplProps) {
function Config({ configs }: ConfigImplProps) {
const [latencyTestUrl, setLatencyTestUrl] = useAtom(latencyTestUrlAtom);
const [selectedChartStyleIndex, setSelectedChartStyleIndex] = useAtom(selectedChartStyleIndexAtom);
const [selectedChartStyleIndex, setSelectedChartStyleIndex] = useAtom(
selectedChartStyleIndexAtom,
);
const apiConfig = useApiConfig();
const [configState, setConfigStateInternal] = useState(configs);
const refConfigs = useRef(configs);
Expand All @@ -93,8 +80,9 @@ function ConfigImpl({ dispatch, configs }: ConfigImplProps) {
}, [configs]);

const openAPIConfigModal = useCallback(() => {
dispatch(openModal('apiConfig'));
}, [dispatch]);
redirect('/backend');
// dispatch(openModal('apiConfig'));
}, []);

const setConfigState = useCallback(
(name: keyof ClashGeneralConfig, val: ClashGeneralConfig[keyof ClashGeneralConfig]) => {
Expand All @@ -103,14 +91,22 @@ function ConfigImpl({ dispatch, configs }: ConfigImplProps) {
[configState],
);

const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: updateConfigs(apiConfig),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['/configs'] });
},
});

const handleSwitchOnChange = useCallback(
(checked: boolean) => {
const name = 'allow-lan';
const value = checked;
setConfigState(name, value);
dispatch(updateConfigs(apiConfig, { 'allow-lan': value }));
mutation.mutate({ 'allow-lan': value });
},
[apiConfig, dispatch, setConfigState],
[mutation, setConfigState],
);

const handleChangeValue = useCallback(
Expand All @@ -119,7 +115,7 @@ function ConfigImpl({ dispatch, configs }: ConfigImplProps) {
case 'mode':
case 'log-level':
setConfigState(name, value);
dispatch(updateConfigs(apiConfig, { [name]: value }));
mutation.mutate({ [name]: value });
if (name === 'log-level') {
logsApi.reconnect({ ...apiConfig, logLevel: value });
}
Expand All @@ -138,16 +134,19 @@ function ConfigImpl({ dispatch, configs }: ConfigImplProps) {
return;
}
},
[apiConfig, dispatch, setConfigState],
[apiConfig, mutation, setConfigState],
);

const handleInputOnChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>(
(e) => handleChangeValue(e.target),
[handleChangeValue],
);
const selectChartStyleIndex = useCallback((idx: number) => {
setSelectedChartStyleIndex(idx);
}, [setSelectedChartStyleIndex])
const selectChartStyleIndex = useCallback(
(idx: number) => {
setSelectedChartStyleIndex(idx);
},
[setSelectedChartStyleIndex],
);

const handleInputOnBlur = useCallback<React.FocusEventHandler<HTMLInputElement>>(
(e) => {
Expand All @@ -160,7 +159,7 @@ function ConfigImpl({ dispatch, configs }: ConfigImplProps) {
case 'redir-port': {
const num = parseInt(value, 10);
if (num < 0 || num > 65535) return;
dispatch(updateConfigs(apiConfig, { [name]: num }));
mutation.mutate({ [name]: num });
break;
}
case 'latencyTestUrl': {
Expand All @@ -171,7 +170,7 @@ function ConfigImpl({ dispatch, configs }: ConfigImplProps) {
throw new Error(`unknown input name ${name}`);
}
},
[apiConfig, dispatch, setLatencyTestUrl],
[mutation, setLatencyTestUrl],
);

const mode = useMemo(() => {
Expand Down
18 changes: 5 additions & 13 deletions src/components/Logs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { connect } from 'src/components/StateProvider';
import SvgYacd from 'src/components/SvgYacd';
import useRemainingViewPortHeight from 'src/hooks/useRemainingViewPortHeight';
import { logStreamingPausedAtom, useApiConfig } from 'src/store/app';
import { getLogLevel } from 'src/store/configs';
import { appendLog, getLogsForDisplay } from 'src/store/logs';
import { DispatchFn, Log, State } from 'src/store/types';

import { useClashConfig } from '$src/store/configs';

import s from './Logs.module.scss';
import { Fab, position as fabPosition } from './shared/Fab';

Expand All @@ -28,8 +29,6 @@ const colors = {
error: '#c11c1c',
};

// type LogLineProps = Partial<Log>;

function LogLine({ time, even, payload, type }: Log) {
const className = cx({ even }, 'log');
return (
Expand Down Expand Up @@ -61,15 +60,9 @@ const Row = memo(({ index, style, data }: ListChildComponentProps<Log[]>) => {

Row.displayName = 'MemoRow';

function Logs({
dispatch,
logLevel,
logs,
}: {
dispatch: DispatchFn;
logLevel: string;
logs: Log[];
}) {
function Logs({ dispatch, logs }: { dispatch: DispatchFn; logs: Log[] }) {
const { data } = useClashConfig();
const logLevel = data['log-level'];
const [logStreamingPaused, setLogStreamingPaused] = useAtom(logStreamingPausedAtom);
const apiConfig = useApiConfig();
const toggleIsRefreshPaused = useCallback(() => {
Expand Down Expand Up @@ -128,7 +121,6 @@ function Logs({

const mapState = (s: State) => ({
logs: getLogsForDisplay(s),
logLevel: getLogLevel(s),
});

export default connect(mapState)(Logs);
2 changes: 1 addition & 1 deletion src/components/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Head } from 'src/components/shared/Head';
import { queryClient } from 'src/misc/query';

import { AppConfigSideEffect } from '$src/components/fn/AppConfigSideEffect';
import { darkModePureBlackToggleAtom } from '$src/store/app';
import { darkModePureBlackToggleAtom } from '$src/store/app';

import { actions, initialState } from '../store';
import APIConfig from './APIConfig';
Expand Down
2 changes: 1 addition & 1 deletion src/components/fn/AppConfigSideEffect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function AppConfigSideEffect() {
selectedChartStyleIndex,
selectedClashAPIConfigIndex,
theme,
}
};
save();
}, [
autoCloseOldConns,
Expand Down
7 changes: 1 addition & 6 deletions src/components/form/Toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import React, {
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';

import s0 from './Toggle.module.scss';

Expand Down
11 changes: 7 additions & 4 deletions src/components/shared/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ export function ThemeSwitcher() {
}
}, [theme]);

const onSelect = React.useCallback((v: ThemeType) => {
setThemeAtom(v);
setTheme(v);
}, [setThemeAtom]);
const onSelect = React.useCallback(
(v: ThemeType) => {
setThemeAtom(v);
setTheme(v);
},
[setThemeAtom],
);

return (
<Menu>
Expand Down
Loading

0 comments on commit 3232bf2

Please sign in to comment.