diff options
| author | Haishan <[email protected]> | 2022-05-08 18:37:08 +0800 |
|---|---|---|
| committer | Haishan <[email protected]> | 2022-05-08 23:30:24 +0800 |
| commit | e8f927bfd3faa6234674fa256010f0e2f53339e0 (patch) | |
| tree | 64246333af7cd800053078404cc5777c88f1414d /src | |
| parent | 3458ef250de9b26bcff4522479708ca9fa5a553c (diff) | |
Upgrade chart.js
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/connections.ts | 1 | ||||
| -rw-r--r-- | src/api/traffic.ts | 30 | ||||
| -rw-r--r-- | src/app.tsx | 10 | ||||
| -rw-r--r-- | src/components/Connections.tsx | 2 | ||||
| -rw-r--r-- | src/components/Root.tsx | 12 | ||||
| -rw-r--r-- | src/components/Rules.tsx | 10 | ||||
| -rw-r--r-- | src/components/StateProvider.tsx | 36 | ||||
| -rw-r--r-- | src/components/StyleGuide.tsx | 11 | ||||
| -rw-r--r-- | src/components/SwitchThemed.tsx | 13 | ||||
| -rw-r--r-- | src/components/ToggleSwitch.tsx | 3 | ||||
| -rw-r--r-- | src/components/TrafficChart.tsx | 10 | ||||
| -rw-r--r-- | src/components/TrafficChartSample.tsx | 24 | ||||
| -rw-r--r-- | src/hooks/useLineChart.ts | 24 | ||||
| -rw-r--r-- | src/misc/chart-lib.ts | 23 | ||||
| -rw-r--r-- | src/misc/chart.ts | 73 | ||||
| -rw-r--r-- | src/misc/constants.ts | 1 | ||||
| -rw-r--r-- | src/misc/sentry.ts | 10 | ||||
| -rw-r--r-- | src/store/app.ts | 1 | ||||
| -rw-r--r-- | src/store/types.ts | 6 |
19 files changed, 128 insertions, 172 deletions
diff --git a/src/api/connections.ts b/src/api/connections.ts index d4ed58e..9c94d31 100644 --- a/src/api/connections.ts +++ b/src/api/connections.ts @@ -29,6 +29,7 @@ export type ConnectionItem = { chains: string[]; // e.g. 'Match', 'DomainKeyword' rule: string; + rulePayload?: string; }; type ConnectionsData = { downloadTotal: number; diff --git a/src/api/traffic.ts b/src/api/traffic.ts index e50ec5e..cd18aac 100644 --- a/src/api/traffic.ts +++ b/src/api/traffic.ts @@ -1,31 +1,33 @@ +import { ClashAPIConfig } from '$src/types'; + import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper'; + const endpoint = '/traffic'; const textDecoder = new TextDecoder('utf-8'); const Size = 150; const traffic = { - labels: Array(Size), - // labels: [], + labels: Array(Size).fill(0), up: Array(Size), down: Array(Size), size: Size, subscribers: [], - appendData(o) { + appendData(o: { up: number; down: number }) { + this.up.shift(); + this.down.shift(); + this.labels.shift(); + + const l = Date.now(); this.up.push(o.up); this.down.push(o.down); - const t = new Date(); - const l = '' + t.getMinutes() + t.getSeconds(); this.labels.push(l); - if (this.up.length > this.size) this.up.shift(); - if (this.down.length > this.size) this.down.shift(); - if (this.labels.length > this.size) this.labels.shift(); this.subscribers.forEach((f) => f(o)); }, - subscribe(listener) { + subscribe(listener: (x:any) => void) { this.subscribers.push(listener); return () => { const idx = this.subscribers.indexOf(listener); @@ -37,11 +39,11 @@ const traffic = { let fetched = false; let decoded = ''; -function parseAndAppend(x) { +function parseAndAppend(x: string) { traffic.appendData(JSON.parse(x)); } -function pump(reader) { +function pump(reader: ReadableStreamDefaultReader) { return reader.read().then(({ done, value }) => { const str = textDecoder.decode(value, { stream: !done }); decoded += str; @@ -73,8 +75,8 @@ function pump(reader) { // other value CLOSED // similar to ws readyState but not the same // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState -let wsState; -function fetchData(apiConfig) { +let wsState: number; +function fetchData(apiConfig: ClashAPIConfig) { if (fetched || wsState === 1) return traffic; wsState = 1; const url = buildWebSocketURL(apiConfig, endpoint); @@ -92,7 +94,7 @@ function fetchData(apiConfig) { return traffic; } -function fetchDataWithFetch(apiConfig) { +function fetchDataWithFetch(apiConfig: ClashAPIConfig) { if (fetched) return traffic; fetched = true; const { url, init } = getURLAndInit(apiConfig); diff --git a/src/app.tsx b/src/app.tsx index 94ee328..64e19ee 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,22 +1,22 @@ import 'modern-normalize/modern-normalize.css'; import './misc/i18n'; -import React from 'react'; -import ReactDOM from 'react-dom'; +import * as React from 'react'; +import { createRoot } from 'react-dom/client'; import Modal from 'react-modal'; import Root from './components/Root'; import * as swRegistration from './swRegistration'; const rootEl = document.getElementById('app'); +const root = createRoot(rootEl); Modal.setAppElement(rootEl); -ReactDOM.render( +root.render( <React.StrictMode> <Root /> - </React.StrictMode>, - rootEl + </React.StrictMode> ); swRegistration.register(); diff --git a/src/components/Connections.tsx b/src/components/Connections.tsx index 2c82fa6..435345b 100644 --- a/src/components/Connections.tsx +++ b/src/components/Connections.tsx @@ -88,7 +88,7 @@ function formatConnectionDataItem( download, start: now - new Date(start).valueOf(), chains: chains.reverse().join(' / '), - rule: (rulePayload == null | rulePayload === '') ? rule : (`${rule}(${rulePayload})`), + rule: !rulePayload ? rule : `${rule}(${rulePayload})`, ...metadata, host: `${host2}:${destinationPort}`, type: `${type}(${network})`, diff --git a/src/components/Root.tsx b/src/components/Root.tsx index f94d2a2..d4a8aa0 100644 --- a/src/components/Root.tsx +++ b/src/components/Root.tsx @@ -3,9 +3,9 @@ import '@fontsource/roboto-mono/latin-400.css'; import '@fontsource/open-sans/latin-400.css'; import '@fontsource/open-sans/latin-700.css'; -import React, { lazy, Suspense } from 'react'; +import * as React from 'react'; import { QueryClientProvider } from 'react-query'; -import { PartialRouteObject } from 'react-router'; +import { RouteObject } from 'react-router'; import { HashRouter as Router, useRoutes } from 'react-router-dom'; import { RecoilRoot } from 'recoil'; import { About } from 'src/components/about/About'; @@ -24,6 +24,8 @@ import SideBar from './SideBar'; import StateProvider from './StateProvider'; import StyleGuide from './StyleGuide'; +const { lazy, Suspense } = React; + const Connections = lazy(() => import('./Connections')); const Config = lazy(() => import('./Config')); const Logs = lazy(() => import('./Logs')); @@ -38,10 +40,8 @@ const routes = [ { path: '/proxies', element: <Proxies /> }, { path: '/rules', element: <Rules /> }, { path: '/about', element: <About /> }, - process.env.NODE_ENV === 'development' - ? { path: '/style', element: <StyleGuide /> } - : false, -].filter(Boolean) as PartialRouteObject[]; + process.env.NODE_ENV === 'development' ? { path: '/style', element: <StyleGuide /> } : false, +].filter(Boolean) as RouteObject[]; function RouteInnerApp() { return useRoutes(routes); diff --git a/src/components/Rules.tsx b/src/components/Rules.tsx index 9019fab..47644e7 100644 --- a/src/components/Rules.tsx +++ b/src/components/Rules.tsx @@ -20,7 +20,13 @@ const { memo } = React; const paddingBottom = 30; -function itemKey(index: number, { rules, provider }) { +type ItemData = { + rules: any[]; + provider: any; + apiConfig: ClashAPIConfig; +}; + +function itemKey(index: number, { rules, provider }: ItemData) { const providerQty = provider.names.length; if (index < providerQty) { @@ -88,10 +94,8 @@ function Rules({ apiConfig }: RulesProps) { <ContentHeader title={t('Rules')} /> <TextFilter placeholder="Filter" textAtom={ruleFilterText} /> </div> - {/* @ts-expect-error ts-migrate(2322) FIXME: Type 'number | MutableRefObject<any>' is not assig... Remove this comment to see the full error message */} <div ref={refRulesContainer} style={{ paddingBottom }}> <VariableSizeList - // @ts-expect-error ts-migrate(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message height={containerHeight - paddingBottom} width="100%" itemCount={rules.length + provider.names.length} diff --git a/src/components/StateProvider.tsx b/src/components/StateProvider.tsx index 6769108..1ef48d7 100644 --- a/src/components/StateProvider.tsx +++ b/src/components/StateProvider.tsx @@ -6,16 +6,8 @@ import React from 'react'; // this is just workaround immer.setAutoFreeze(false); -const { - createContext, - memo, - useMemo, - useRef, - useEffect, - useCallback, - useContext, - useState, -} = React; +const { createContext, memo, useMemo, useRef, useEffect, useCallback, useContext, useState } = + React; export { immer }; @@ -46,7 +38,7 @@ export default function Provider({ initialState, actions = {}, children }) { } }, [getState]); const dispatch = useCallback( - (actionId, fn) => { + (actionId: string | ((a: any, b: any) => any), fn: (s: any) => void) => { if (typeof actionId === 'function') return actionId(dispatch, getState); const stateNext = produce(getState(), fn); @@ -61,26 +53,21 @@ export default function Provider({ initialState, actions = {}, children }) { }, [getState] ); - const boundActions = useMemo(() => bindActions(actions, dispatch), [ - actions, - dispatch, - ]); + const boundActions = useMemo(() => bindActions(actions, dispatch), [actions, dispatch]); return ( <StateContext.Provider value={state}> <DispatchContext.Provider value={dispatch}> - <ActionsContext.Provider value={boundActions}> - {children} - </ActionsContext.Provider> + <ActionsContext.Provider value={boundActions}>{children}</ActionsContext.Provider> </DispatchContext.Provider> </StateContext.Provider> ); } -export function connect(mapStateToProps) { - return (Component) => { +export function connect(mapStateToProps: any) { + return (Component: any) => { const MemoComponent = memo(Component); - function Connected(props) { + function Connected(props: any) { const state = useContext(StateContext); const dispatch = useContext(DispatchContext); const mapped = mapStateToProps(state, props); @@ -92,14 +79,13 @@ export function connect(mapStateToProps) { } // steal from https://github.com/reduxjs/redux/blob/master/src/bindActionCreators.ts -function bindAction(action, dispatch) { - return function (...args) { - // @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message +function bindAction(action: any, dispatch: any) { + return function (...args: any[]) { return dispatch(action.apply(this, args)); }; } -function bindActions(actions, dispatch) { +function bindActions(actions: any, dispatch: any) { const boundActions = {}; for (const key in actions) { const action = actions[key]; diff --git a/src/components/StyleGuide.tsx b/src/components/StyleGuide.tsx index ec0c29b..ee38697 100644 --- a/src/components/StyleGuide.tsx +++ b/src/components/StyleGuide.tsx @@ -21,9 +21,7 @@ const optionsRule = [ { label: 'Direct', value: 'Direct' }, ]; -const Pane = ({ children, style }) => ( - <div style={{ ...paneStyle, ...style }}>{children}</div> -); +const Pane = ({ children, style }) => <div style={{ ...paneStyle, ...style }}>{children}</div>; function useToggle(initialState = false) { const [onoff, setonoff] = React.useState(initialState); @@ -52,12 +50,7 @@ class StyleGuide extends PureComponent { </Pane> {/* @ts-expect-error ts-migrate(2741) FIXME: Property 'style' is missing in type '{ children: E... Remove this comment to see the full error message */} <Pane> - <ToggleSwitch - name="test" - options={optionsRule} - value="Rule" - onChange={noop} - /> + <ToggleSwitch name="test" options={optionsRule} value="Rule" onChange={noop} /> </Pane> {/* @ts-expect-error ts-migrate(2741) FIXME: Property 'style' is missing in type '{ children: E... Remove this comment to see the full error message */} <Pane> diff --git a/src/components/SwitchThemed.tsx b/src/components/SwitchThemed.tsx index 7121acb..7289bd2 100644 --- a/src/components/SwitchThemed.tsx +++ b/src/components/SwitchThemed.tsx @@ -1,11 +1,14 @@ -import React from 'react'; -import S from 'react-switch'; +import * as React from 'react'; +import ReactSwitch from 'react-switch'; + +import { State } from '$src/store/types'; import { getTheme } from '../store/app'; import { connect } from './StateProvider'; // workaround https://github.com/vitejs/vite/issues/2139#issuecomment-802981228 -const Switch = S.default ? S.default : S; +// @ts-ignore +const Switch = ReactSwitch.default ? ReactSwitch.default : ReactSwitch; function SwitchThemed({ checked = false, onChange, theme, name }) { const offColor = theme === 'dark' ? '#393939' : '#e9e9e9'; @@ -29,6 +32,4 @@ function SwitchThemed({ checked = false, onChange, theme, name }) { ); } -export default connect((s) => ({ - theme: getTheme(s), -}))(SwitchThemed); +export default connect((s: State) => ({ theme: getTheme(s) }))(SwitchThemed); diff --git a/src/components/ToggleSwitch.tsx b/src/components/ToggleSwitch.tsx index 0c84059..9eb1019 100644 --- a/src/components/ToggleSwitch.tsx +++ b/src/components/ToggleSwitch.tsx @@ -16,8 +16,7 @@ function ToggleSwitch({ options, value, name, onChange }: Props) { ); const getPortionPercentage = useCallback( - // @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value. - (idx) => { + (idx: number) => { const w = Math.floor(100 / options.length); if (idx === options.length - 1) { return 100 - options.length * w + w; diff --git a/src/components/TrafficChart.tsx b/src/components/TrafficChart.tsx index 056cac6..367166a 100644 --- a/src/components/TrafficChart.tsx +++ b/src/components/TrafficChart.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; +import { State } from '$src/store/types'; + import { fetchData } from '../api/traffic'; import useLineChart from '../hooks/useLineChart'; import { @@ -19,7 +21,7 @@ const chartWrapperStyle = { maxWidth: 1000, }; -const mapState = (s) => ({ +const mapState = (s: State) => ({ apiConfig: getClashAPIConfig(s), selectedChartStyleIndex: getSelectedChartStyleIndex(s), }); @@ -27,7 +29,7 @@ const mapState = (s) => ({ export default connect(mapState)(TrafficChart); function TrafficChart({ apiConfig, selectedChartStyleIndex }) { - const Chart = chartJSResource.read(); + const ChartMod = chartJSResource.read(); const traffic = fetchData(apiConfig); const { t } = useTranslation(); const data = useMemo( @@ -48,10 +50,10 @@ function TrafficChart({ apiConfig, selectedChartStyleIndex }) { }, ], }), - [traffic, selectedChartStyleIndex, t] + [ traffic, selectedChartStyleIndex, t] ); - useLineChart(Chart, 'trafficChart', data, traffic); + useLineChart(ChartMod.Chart, 'trafficChart', data, traffic); return ( // @ts-expect-error ts-migrate(2322) FIXME: Type '{ position: string; maxWidth: number; }' is ... Remove this comment to see the full error message diff --git a/src/components/TrafficChartSample.tsx b/src/components/TrafficChartSample.tsx index fb9b2ee..3e0bba3 100644 --- a/src/components/TrafficChartSample.tsx +++ b/src/components/TrafficChartSample.tsx @@ -1,19 +1,17 @@ -import React, { useMemo } from 'react'; +import * as React from 'react'; import useLineChart from '../hooks/useLineChart'; -import { - chartJSResource, - chartStyles, - commonDataSetProps, -} from '../misc/chart'; +import { chartJSResource, chartStyles, commonDataSetProps } from '../misc/chart'; -const extraChartOptions = { - legend: { - display: false, +const { useMemo } = React; + +const extraChartOptions: import('chart.js').ChartOptions<'line'> = { + plugins: { + legend: { display: false }, }, scales: { - xAxes: [{ display: false }], - yAxes: [{ display: false }], + x: { display: false, type: 'category' }, + y: { display: false, type: 'linear' }, }, }; @@ -22,7 +20,7 @@ const data2 = [184e3, 183e3, 196e3, 182e3, 190e3, 186e3, 182e3, 189e3]; const labels = data1; export default function TrafficChart({ id }) { - const Chart = chartJSResource.read(); + const ChartMod = chartJSResource.read(); const data = useMemo( () => ({ @@ -44,7 +42,7 @@ export default function TrafficChart({ id }) { ); const eleId = 'chart-' + id; - useLineChart(Chart, eleId, data, null, extraChartOptions); + useLineChart(ChartMod.Chart, eleId, data, null, extraChartOptions); return ( <div style={{ width: 100, padding: 5 }}> diff --git a/src/hooks/useLineChart.ts b/src/hooks/useLineChart.ts index 2757ee1..a3205aa 100644 --- a/src/hooks/useLineChart.ts +++ b/src/hooks/useLineChart.ts @@ -1,28 +1,24 @@ +import type { ChartConfiguration } from 'chart.js'; import React from 'react'; import { commonChartOptions } from 'src/misc/chart'; const { useEffect } = React; -const options = commonChartOptions; export default function useLineChart( - Chart, - elementId, - data, - subscription, + chart: typeof import('chart.js').Chart, + elementId: string, + data: ChartConfiguration['data'], + subscription: any, extraChartOptions = {} ) { useEffect(() => { - const ctx = document.getElementById(elementId).getContext('2d'); - const c = new Chart(ctx, { - type: 'line', - data, - options: { ...options, ...extraChartOptions }, - }); - const unsubscribe = - subscription && subscription.subscribe(() => c.update()); + const ctx = (document.getElementById(elementId) as HTMLCanvasElement).getContext('2d'); + const options = { ...commonChartOptions, ...extraChartOptions }; + const c = new chart(ctx, { type: 'line', data, options }); + const unsubscribe = subscription && subscription.subscribe(() => c.update()); return () => { unsubscribe && unsubscribe(); c.destroy(); }; - }, [Chart, elementId, data, subscription, extraChartOptions]); + }, [chart, elementId, data, subscription, extraChartOptions]); } diff --git a/src/misc/chart-lib.ts b/src/misc/chart-lib.ts new file mode 100644 index 0000000..9a2bf35 --- /dev/null +++ b/src/misc/chart-lib.ts @@ -0,0 +1,23 @@ +import { + CategoryScale, + Chart, + Filler, + Legend, + LinearScale, + LineController, + LineElement, + PointElement, +} from 'chart.js'; + +// see https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc +Chart.register( + LineElement, + PointElement, + LineController, + CategoryScale, + LinearScale, + Filler, + Legend +); + +export { Chart }; diff --git a/src/misc/chart.ts b/src/misc/chart.ts index 9e2c459..a6ee82e 100644 --- a/src/misc/chart.ts +++ b/src/misc/chart.ts @@ -1,71 +1,36 @@ import { unstable_createResource as createResource } from '@hsjs/react-cache'; import prettyBytes from './pretty-bytes'; - export const chartJSResource = createResource(() => { - return import( - /* webpackChunkName: "chartjs" */ - /* webpackPrefetch: true */ - /* webpackPreload: true */ - 'chart.js/dist/Chart.min.js' - ).then((c) => c.default); + return import('$src/misc/chart-lib'); }); -export const commonDataSetProps = { - borderWidth: 1, - lineTension: 0, - pointRadius: 0, -}; +export const commonDataSetProps = { borderWidth: 1, pointRadius: 0, tension: 0.2, fill: true }; -export const commonChartOptions = { +export const commonChartOptions: import('chart.js').ChartOptions<'line'> = { responsive: true, maintainAspectRatio: true, - title: { - display: false, - }, - legend: { - display: true, - position: 'top', - labels: { - fontColor: '#ccc', - boxWidth: 20, - }, - }, - tooltips: { - enabled: false, - mode: 'index', - intersect: false, - animationDuration: 100, - }, - hover: { - mode: 'nearest', - intersect: true, + plugins: { + legend: { labels: { boxWidth: 20 } } }, scales: { - xAxes: [ - { - display: false, - gridLines: { - display: false, - }, - }, - ], - yAxes: [ - { + x: { display: false, type: 'category' }, + y: { + type: 'linear', + display: true, + grid: { display: true, - gridLines: { - display: true, - color: '#555', - borderDash: [3, 6], - drawBorder: false, - }, - ticks: { - callback(value) { - return prettyBytes(value) + '/s '; - }, + color: '#555', + drawTicks: false, + borderDash: [3, 6], + drawBorder: false, + }, + ticks: { + callback(value: number) { + return prettyBytes(value) + '/s '; }, }, - ], + }, }, }; diff --git a/src/misc/constants.ts b/src/misc/constants.ts deleted file mode 100644 index 5c66350..0000000 --- a/src/misc/constants.ts +++ /dev/null @@ -1 +0,0 @@ -// const ProxySortingOptions = diff --git a/src/misc/sentry.ts b/src/misc/sentry.ts deleted file mode 100644 index efedcb3..0000000 --- a/src/misc/sentry.ts +++ /dev/null @@ -1,10 +0,0 @@ -const dsn = 'https://[email protected]/1359284'; -let Sentry; -export async function getSentry() { - if (Sentry) return Sentry; - const s = await import('@sentry/browser'); - s.init({ dsn }); - // eslint-disable-next-line require-atomic-updates - Sentry = s; - return Sentry; -} diff --git a/src/store/app.ts b/src/store/app.ts index 6680e6e..7262b32 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -22,7 +22,6 @@ export const getLogStreamingPaused = (s: State) => s.app.logStreamingPaused; const saveStateDebounced = debounce(saveState, 600); -// @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value. function findClashAPIConfigIndex(getState: GetStateFn, { baseURL, secret }) { const arr = getClashAPIConfigs(getState()); for (let i = 0; i < arr.length; i++) { diff --git a/src/store/types.ts b/src/store/types.ts index b9141ac..d12adaa 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -108,10 +108,8 @@ export type State = { export type GetStateFn = () => State; export interface DispatchFn { (msg: string, change: (s: State) => void): void; - ( - action: (dispatch: DispatchFn, getState: GetStateFn) => Promise<void> - ): ReturnType<typeof action>; - (action: (dispatch: DispatchFn, getState: GetStateFn) => void): ReturnType< + (action: (dispatch: DispatchFn, getState: GetStateFn) => Promise<void>): ReturnType< typeof action >; + (action: (dispatch: DispatchFn, getState: GetStateFn) => void): ReturnType<typeof action>; } |
