summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaishan <[email protected]>2021-11-12 20:39:01 +0800
committerHaishan <[email protected]>2021-11-12 20:39:01 +0800
commitce3ed3d99f6c8fcc13747c9fea12ce7f6cbebd72 (patch)
tree865e8d6f6d15897dbd4294f7019abbcb68eb5d55
parentb1ea08a4ee8dcb133b6be7dc4282eaffab32c046 (diff)
Add float action button to pause/start log streaming
-rw-r--r--package.json4
-rw-r--r--prettier.config.js3
-rw-r--r--src/api/logs.ts21
-rw-r--r--src/components/Connections.tsx6
-rw-r--r--src/components/Logs.tsx54
-rw-r--r--src/components/Root.scss12
6 files changed, 50 insertions, 50 deletions
diff --git a/package.json b/package.json
index a76251c..e449804 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,10 @@
"name": "yacd",
"version": "0.3.3",
"description": "Yet another Clash dashboard",
+ "prettier": {
+ "printWidth": 100,
+ "singleQuote": true
+ },
"scripts": {
"lint": "eslint --fix --cache src",
"dev": "vite",
diff --git a/prettier.config.js b/prettier.config.js
deleted file mode 100644
index 7d93e18..0000000
--- a/prettier.config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- singleQuote: true
-};
diff --git a/src/api/logs.ts b/src/api/logs.ts
index cb74bf3..044a31b 100644
--- a/src/api/logs.ts
+++ b/src/api/logs.ts
@@ -5,6 +5,12 @@ import { LogsAPIConfig } from 'src/types';
import { buildLogsWebSocketURL, getURLAndInit } from '../misc/request-helper';
type AppendLogFn = (x: Log) => void;
+enum WebSocketReadyState {
+ Connecting = 0,
+ Open = 1,
+ Closing = 2,
+ Closed = 3,
+}
const endpoint = '/logs';
const textDecoder = new TextDecoder('utf-8');
@@ -86,20 +92,13 @@ function makeConnStr(c: LogsAPIConfig) {
let prevConnStr: string;
let controller: AbortController;
-// 1 OPEN
-// other value CLOSED
-// similar to ws readyState but not the same
-// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState
-let wsState: number;
export function fetchLogs(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) {
if (apiConfig.logLevel === 'uninit') return;
- if (fetched || wsState === 1) return;
+ if (fetched || (ws && ws.readyState === WebSocketReadyState.Open)) return;
prevAppendLogFn = appendLog;
- wsState = 1;
const url = buildLogsWebSocketURL(apiConfig, endpoint);
ws = new WebSocket(url);
ws.addEventListener('error', () => {
- wsState = 3;
fetchLogsWithFetch(apiConfig, appendLog);
});
ws.addEventListener('message', function (event) {
@@ -107,10 +106,14 @@ export function fetchLogs(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) {
});
}
+export function stop() {
+ ws.close();
+ if (controller) controller.abort();
+}
+
export function reconnect(apiConfig: LogsAPIConfig) {
if (!prevAppendLogFn || !ws) return;
ws.close();
- wsState = 3;
fetched = false;
fetchLogs(apiConfig, prevAppendLogFn);
}
diff --git a/src/components/Connections.tsx b/src/components/Connections.tsx
index e5b4466..4c8bcff 100644
--- a/src/components/Connections.tsx
+++ b/src/components/Connections.tsx
@@ -235,11 +235,7 @@ function Conn({ apiConfig }) {
isRefreshPaused ? <Play size={16} /> : <Pause size={16} />
}
mainButtonStyles={
- isRefreshPaused
- ? {
- background: '#e74c3c',
- }
- : {}
+ isRefreshPaused ? { background: '#e74c3c' } : {}
}
style={fabPosition}
text={isRefreshPaused ? 'Resume Refresh' : 'Pause Refresh'}
diff --git a/src/components/Logs.tsx b/src/components/Logs.tsx
index 019edd5..8f4ed1e 100644
--- a/src/components/Logs.tsx
+++ b/src/components/Logs.tsx
@@ -1,12 +1,8 @@
import cx from 'clsx';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
-import {
- areEqual,
- FixedSizeList as List,
- ListChildComponentProps,
-} from 'react-window';
-import { fetchLogs } from 'src/api/logs';
+import { areEqual, FixedSizeList as List, ListChildComponentProps } from 'react-window';
+import { fetchLogs, stop as stopLogs, reconnect as reconnectLogs } from 'src/api/logs';
import ContentHeader from 'src/components/ContentHeader';
import LogSearch from 'src/components/LogSearch';
import { connect } from 'src/components/StateProvider';
@@ -16,10 +12,12 @@ import { getClashAPIConfig } from 'src/store/app';
import { getLogLevel } from 'src/store/configs';
import { appendLog, getLogsForDisplay } from 'src/store/logs';
import { Log, State } from 'src/store/types';
+import { Pause, Play } from 'react-feather';
+import { Fab, position as fabPosition } from './shared/Fab';
import s from './Logs.module.scss';
-const { useCallback, memo, useEffect } = React;
+const { useState, useCallback, memo, useEffect } = React;
const paddingBottom = 30;
const colors = {
@@ -51,23 +49,22 @@ function itemKey(index: number, data: LogLineProps[]) {
return item.id;
}
-const Row = memo(
- ({ index, style, data }: ListChildComponentProps<LogLineProps>) => {
- const r = data[index];
- return (
- <div style={style}>
- <LogLine {...r} />
- </div>
- );
- },
- areEqual
-);
+const Row = memo(({ index, style, data }: ListChildComponentProps<LogLineProps>) => {
+ const r = data[index];
+ return (
+ <div style={style}>
+ <LogLine {...r} />
+ </div>
+ );
+}, areEqual);
function Logs({ dispatch, logLevel, apiConfig, logs }) {
- const appendLogInternal = useCallback(
- (log) => dispatch(appendLog(log)),
- [dispatch]
- );
+ const [isRefreshPaused, setIsRefreshPaused] = useState(false);
+ const toggleIsRefreshPaused = useCallback(() => {
+ isRefreshPaused ? reconnectLogs({ ...apiConfig, logLevel }) : stopLogs();
+ setIsRefreshPaused((x) => !x);
+ }, [isRefreshPaused, apiConfig, logLevel]);
+ const appendLogInternal = useCallback((log) => dispatch(appendLog(log)), [dispatch]);
useEffect(() => {
fetchLogs({ ...apiConfig, logLevel }, appendLogInternal);
}, [apiConfig, logLevel, appendLogInternal]);
@@ -80,10 +77,7 @@ function Logs({ dispatch, logLevel, apiConfig, logs }) {
<LogSearch />
<div ref={refLogsContainer} style={{ paddingBottom }}>
{logs.length === 0 ? (
- <div
- className={s.logPlaceholder}
- style={{ height: containerHeight - paddingBottom }}
- >
+ <div className={s.logPlaceholder} style={{ height: containerHeight - paddingBottom }}>
<div className={s.logPlaceholderIcon}>
<SvgYacd width={200} height={200} />
</div>
@@ -101,6 +95,14 @@ function Logs({ dispatch, logLevel, apiConfig, logs }) {
>
{Row}
</List>
+
+ <Fab
+ icon={isRefreshPaused ? <Play size={16} /> : <Pause size={16} />}
+ mainButtonStyles={isRefreshPaused ? { background: '#e74c3c' } : {}}
+ style={fabPosition}
+ text={isRefreshPaused ? 'Resume Refresh' : 'Pause Refresh'}
+ onClick={toggleIsRefreshPaused}
+ ></Fab>
</div>
)}
</div>
diff --git a/src/components/Root.scss b/src/components/Root.scss
index 55198ab..0df5819 100644
--- a/src/components/Root.scss
+++ b/src/components/Root.scss
@@ -53,18 +53,14 @@
:root {
--font-mono: 'Roboto Mono', Menlo, monospace;
- --font-normal: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica,
- Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol,
- 'PingFang SC', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
+ // prettier-ignore
+ --font-normal: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, 'PingFang SC', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
--color-focus-blue: #1a73e8;
--btn-bg: #387cec;
}
body {
- font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
- Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji,
- Segoe UI Symbol, 'PingFang SC', 'Microsoft YaHei', '微软雅黑', Arial,
- sans-serif;
+ font-family: var(--font-normal);
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
@@ -135,10 +131,12 @@ body {
:root[data-theme='dark'] {
@include dark;
+ color-scheme: dark;
}
:root[data-theme='light'] {
@include light;
+ color-scheme: light;
}
.flexCenter {