From 78e55d115a22f185c5cc7775dbbebc1d98556cce Mon Sep 17 00:00:00 2001 From: PuQing Date: Mon, 27 Nov 2023 18:40:54 +0800 Subject: [PATCH 001/114] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 291a2724..64bb808f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # NEETBOX -[![wakatime](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c.svg)](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c) +[![wakatime](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c.svg)](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c) [![Run pytest](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml/badge.svg)](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml) [![PyPI version](https://badge.fury.io/py/neetbox.svg)](https://badge.fury.io/py/neetbox) ![](./doc/static/img/readme.png) From 2bd2f4921b93af35c89d3263736db58124e4e025 Mon Sep 17 00:00:00 2001 From: VisualDust Date: Mon, 27 Nov 2023 18:41:39 +0800 Subject: [PATCH 002/114] fixed missing color on logs --- neetbox/config/_config.py | 2 +- .../src/components/dashboard/project/logs.tsx | 13 ++++++++----- tests/client/neetbox.toml | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/neetbox/config/_config.py b/neetbox/config/_config.py index 91bb9d1e..427f3ffd 100644 --- a/neetbox/config/_config.py +++ b/neetbox/config/_config.py @@ -17,7 +17,7 @@ }, "daemon": { "enable": True, - "host": "localhost", + "host": "127.0.0.1", "port": 20202, "displayName": None, "allowIpython": False, diff --git a/neetbox/frontend/src/components/dashboard/project/logs.tsx b/neetbox/frontend/src/components/dashboard/project/logs.tsx index b920bfee..34c431d2 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs.tsx +++ b/neetbox/frontend/src/components/dashboard/project/logs.tsx @@ -62,16 +62,19 @@ const LogItemContainer = styled.div` padding: 0 3px; border-radius: 5px; } - .log-prefix-INFO { + .log-prefix-info { background-color: #bbcffc; } - .log-prefix-OK { + .log-prefix-ok { background-color: #a2ffae; } - .log-prefix-WARNING { + .log-prefix-warning { background-color: #ede483; } - .log-prefix-ERROR { + .log-prefix-debug { + background-color: #c483ed; + } + .log-prefix-error { background-color: #ffa2a2; } `; @@ -89,7 +92,7 @@ function getColorFromWhom(whom: string) { const LogItem = React.memo(({ data }: { data: LogData }) => { let { prefix } = data; - if (!prefix) prefix = "LOG"; + if (!prefix) prefix = "log"; return ( {data.datetime}{" "} diff --git a/tests/client/neetbox.toml b/tests/client/neetbox.toml index d7826f47..ef1c82ed 100644 --- a/tests/client/neetbox.toml +++ b/tests/client/neetbox.toml @@ -8,7 +8,7 @@ updateInterval = 0.6 [daemon] enable = true -host = "localhost" +host = "127.0.0.1" port = 5000 allowIpython = false mute = true From 237f94812204529d686ad42289be8acc2028e61a Mon Sep 17 00:00:00 2001 From: PuQing Date: Mon, 27 Nov 2023 18:44:53 +0800 Subject: [PATCH 003/114] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 64bb808f..fd92500b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # NEETBOX -[![wakatime](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c.svg)](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c) [![Run pytest](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml/badge.svg)](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml) [![PyPI version](https://badge.fury.io/py/neetbox.svg)](https://badge.fury.io/py/neetbox) +[![wakatime](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c.svg)](https://wakatime.com/badge/user/b93a26b6-8ea1-44ef-99ed-bcb6e2c732f1/project/8f99904d-dbb1-49e4-814d-8d18bf1e6d1c) [![Run pytest](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml/badge.svg)](https://github.com/visualDust/neetbox/actions/workflows/poetry-pytest.yml) ![PyPI - Version](https://img.shields.io/pypi/v/neetbox) + ![PyPI - Downloads](https://img.shields.io/pypi/dw/neetbox) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) + ![](./doc/static/img/readme.png) From beee145ad98f7bd0269878fbf0f89163963000b8 Mon Sep 17 00:00:00 2001 From: VisualDust Date: Mon, 27 Nov 2023 20:54:44 +0800 Subject: [PATCH 004/114] fixed websocket refuse remote connection --- neetbox/daemon/client/_action_agent.py | 8 ++++++-- neetbox/daemon/server/_server.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/neetbox/daemon/client/_action_agent.py b/neetbox/daemon/client/_action_agent.py index 0ce4de19..561269f4 100644 --- a/neetbox/daemon/client/_action_agent.py +++ b/neetbox/daemon/client/_action_agent.py @@ -12,6 +12,7 @@ from neetbox.pipeline._signal_and_slot import SYSTEM_CHANNEL from neetbox.utils.mvc import Singleton + class PackedAction(Callable): def __init__( self, @@ -35,10 +36,13 @@ def get_props_dict(self): # } _arg_anno_dict = self.function.__annotations__ _args = self.argspec.args - __arg_dict = {_arg_name: _arg_anno_dict.get(_arg_name, any).__name__ for _arg_name in _args} + _arg_dict = {} + for _arg_name in _args: + _arg_type = _arg_anno_dict.get(_arg_name, any) + _arg_dict[_arg_name] = _arg_type if isinstance(_arg_type, str) else _arg_type.__name__ return { "description": self.description, - "args": __arg_dict, + "args": _arg_dict, "blocking": self.blocking, } diff --git a/neetbox/daemon/server/_server.py b/neetbox/daemon/server/_server.py index 5101b317..f025e9fd 100644 --- a/neetbox/daemon/server/_server.py +++ b/neetbox/daemon/server/_server.py @@ -66,7 +66,7 @@ def ws_send(self): app = Flask(__PROC_NAME) # websocket server - ws_server = WebsocketServer(port=cfg["port"] + 1) + ws_server = WebsocketServer(host="0.0.0.0", port=cfg["port"] + 1) __BRIDGES = {} # manage connections connected_clients: Dict(int, Tuple(str, str)) = {} # {cid:(name,type)} store connection only From da313fa5b620286de0c71b4046777f3b16cc4264 Mon Sep 17 00:00:00 2001 From: VisualDust Date: Mon, 27 Nov 2023 20:55:23 +0800 Subject: [PATCH 005/114] edited version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1df8311c..9c45f25d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "neetbox" -version = "0.2.2" +version = "0.2.3" description = "NEETBox contains useless CV code snippets." license = "MIT" authors = ["VisualDust "] From 3ebf63d81b247a4a70e07dc93286b03f24d13baf Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 20:56:39 +0800 Subject: [PATCH 006/114] fix: status TypeError --- .../components/dashboard/project/actions.tsx | 35 ++++++++++++++----- .../dashboard/project/platformProps.tsx | 9 ++--- .../src/pages/console/proejctDashboard.tsx | 10 ++++-- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index 4abcd3e3..6bc840e8 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -17,16 +17,27 @@ interface Props { export function Actions({ actions }: Props) { const [blocking, setBlocking] = useState(false); + const actionList = Object.entries(actions?.value ?? {}); return ( - {Object.entries(actions.value).map(([actionName, actionOptions]) => ( - - ))} + {actionList.length ? ( + actionList.map(([actionName, actionOptions]) => ( + + )) + ) : ( + + No actions ( + + docs + + ) + + )} ); } @@ -65,7 +76,13 @@ export function ActionItem({ )} {Object.entries(options.args).map(([argName, argType]) => ( - + {argName} diff --git a/neetbox/frontend/src/components/dashboard/project/platformProps.tsx b/neetbox/frontend/src/components/dashboard/project/platformProps.tsx index 2eb6df24..641de374 100644 --- a/neetbox/frontend/src/components/dashboard/project/platformProps.tsx +++ b/neetbox/frontend/src/components/dashboard/project/platformProps.tsx @@ -44,7 +44,7 @@ function PropCard({ propName, propValue }): React.JSX.Element { () => { // copy failed Toast.error("Failed to copy"); - } + }, ); }} > @@ -59,9 +59,10 @@ export default function PlatformProps({ data }): React.JSX.Element { return (
- {Object.entries(data.value).map(([key, value]) => ( - - ))} + {(data?.value && + Object.entries(data.value).map(([key, value]) => ( + + ))) || No Platform Info}
); diff --git a/neetbox/frontend/src/pages/console/proejctDashboard.tsx b/neetbox/frontend/src/pages/console/proejctDashboard.tsx index 9ac6f337..e6b0d528 100644 --- a/neetbox/frontend/src/pages/console/proejctDashboard.tsx +++ b/neetbox/frontend/src/pages/console/proejctDashboard.tsx @@ -10,7 +10,7 @@ import { Actions } from "../../components/dashboard/project/actions"; import Loading from "../../components/loading"; export const ProjectContext = createContext<{ projectName: string } | null>( - null + null, ); export default function ProjectDashboardButRecreateOnRouteChange() { @@ -29,7 +29,7 @@ function ProjectDashboard() { () => ({ projectName, }), - [projectName] + [projectName], ); return ( @@ -64,7 +64,11 @@ function Hardware({ }) { return (
- + {hardwareData.every((x) => x.value.cpus) ? ( + + ) : ( + No CPU Info + )}
); } From f0c42f7611893145e961d313db9c7b6489d7ff7c Mon Sep 17 00:00:00 2001 From: VisualDust Date: Mon, 27 Nov 2023 20:58:24 +0800 Subject: [PATCH 007/114] edited version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9c45f25d..03775055 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "neetbox" -version = "0.2.3" +version = "0.2.4" description = "NEETBox contains useless CV code snippets." license = "MIT" authors = ["VisualDust "] From c4a11c1768d88b170e91722629b7376a4cb32dd5 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 21:21:18 +0800 Subject: [PATCH 008/114] fix: logs color in dark mode --- .../src/components/dashboard/project/logs.css | 34 ++++++++++++++++-- .../src/components/dashboard/project/logs.tsx | 35 ++----------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/neetbox/frontend/src/components/dashboard/project/logs.css b/neetbox/frontend/src/components/dashboard/project/logs.css index 5b600d2c..4ef4bbdf 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs.css +++ b/neetbox/frontend/src/components/dashboard/project/logs.css @@ -1,3 +1,33 @@ -[theme-mode="dark"] .log-tag { - background-color: #333; +.log-item { + margin-bottom: 5px; + font-family: "Courier New", Courier, monospace; + font-size: 13px; + + .log-tag { + display: inline-block; + --log-tag-bg-hs: 0, 0%; + --log-tag-bg-l: 80%; + background-color: hsl(var(--log-tag-bg-hs), var(--log-tag-bg-l)); + padding: 0 3px; + border-radius: 5px; + } + .log-prefix-info { + --log-tag-bg-hs: 222, 80%; + } + .log-prefix-ok { + --log-tag-bg-hs: 128, 80%; + } + .log-prefix-warning { + --log-tag-bg-hs: 55, 80%; + } + .log-prefix-debug { + --log-tag-bg-hs: 277, 80%; + } + .log-prefix-error { + --log-tag-bg-hs: 0, 80%; + } +} + +[theme-mode="dark"] .log-item .log-tag { + --log-tag-bg-l: 30%; } diff --git a/neetbox/frontend/src/components/dashboard/project/logs.tsx b/neetbox/frontend/src/components/dashboard/project/logs.tsx index 34c431d2..497bd750 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs.tsx +++ b/neetbox/frontend/src/components/dashboard/project/logs.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from "react"; -import { styled } from "styled-components"; import { LogData, useProjectLogs } from "../../../services/projects"; import "./logs.css"; @@ -51,34 +50,6 @@ const LogItems = ({ logs }: { logs: LogData[] }) => { return logs.map((x) => ); }; -const LogItemContainer = styled.div` - margin-bottom: 5px; - font-family: "Courier New", Courier, monospace; - font-size: 13px; - - .log-tag { - display: inline-block; - background-color: #ddd; - padding: 0 3px; - border-radius: 5px; - } - .log-prefix-info { - background-color: #bbcffc; - } - .log-prefix-ok { - background-color: #a2ffae; - } - .log-prefix-warning { - background-color: #ede483; - } - .log-prefix-debug { - background-color: #c483ed; - } - .log-prefix-error { - background-color: #ffa2a2; - } -`; - function getColorFromWhom(whom: string) { const hue = 50 + @@ -87,14 +58,14 @@ function getColorFromWhom(whom: string) { .reduce((prev, char) => ((prev * 11) % 360) + char.charCodeAt(0), 0) * 233) % 200); - return `hsl(${hue}, 70%, 80%)`; + return `hsl(${hue}, 70%, var(--log-tag-bg-l))`; } const LogItem = React.memo(({ data }: { data: LogData }) => { let { prefix } = data; if (!prefix) prefix = "log"; return ( - +
{data.datetime}{" "} {prefix} @@ -106,6 +77,6 @@ const LogItem = React.memo(({ data }: { data: LogData }) => { {data.whom} {" "} {data.msg} - +
); }); From aa401ed482da56b449d3fcec1ff4a2c83f14a906 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 21:36:45 +0800 Subject: [PATCH 009/114] feat: change routes --- neetbox/frontend/src/App.tsx | 2 +- neetbox/frontend/src/main.tsx | 5 +++-- neetbox/frontend/src/pages/console/index.tsx | 8 ++++++-- neetbox/frontend/src/pages/console/overview.tsx | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/neetbox/frontend/src/App.tsx b/neetbox/frontend/src/App.tsx index 947f1ab5..5661e9bb 100644 --- a/neetbox/frontend/src/App.tsx +++ b/neetbox/frontend/src/App.tsx @@ -24,7 +24,7 @@ export default function AppLayout() { - + diff --git a/neetbox/frontend/src/main.tsx b/neetbox/frontend/src/main.tsx index 17dd5eb0..84f71bb4 100644 --- a/neetbox/frontend/src/main.tsx +++ b/neetbox/frontend/src/main.tsx @@ -4,7 +4,7 @@ import { RouterProvider, createBrowserRouter } from "react-router-dom"; import AppLayout, { Home } from "./App"; import LoginPage from "./pages/login"; import "./index.css"; -import { consoleRoutes } from "./pages/console"; +import Console, { consoleRoutes } from "./pages/console"; import { startBackgroundTasks } from "./services/projects"; const router = createBrowserRouter([ @@ -14,7 +14,8 @@ const router = createBrowserRouter([ children: [ { path: "", - element: , + // element: , + element: , }, consoleRoutes(), { diff --git a/neetbox/frontend/src/pages/console/index.tsx b/neetbox/frontend/src/pages/console/index.tsx index 1290c814..de587efe 100644 --- a/neetbox/frontend/src/pages/console/index.tsx +++ b/neetbox/frontend/src/pages/console/index.tsx @@ -10,7 +10,11 @@ export function consoleRoutes(): RouteObject { path: "console", element: , children: [ - { path: "project/:projectName", element: , errorElement:
Error
}, + { + path: "project/:projectName", + element: , + errorElement:
Error
, + }, { path: "overview", element: }, ], }; @@ -22,7 +26,7 @@ export default class Console extends Component { return ( - + diff --git a/neetbox/frontend/src/pages/console/overview.tsx b/neetbox/frontend/src/pages/console/overview.tsx index 4e0d5b22..1590168a 100644 --- a/neetbox/frontend/src/pages/console/overview.tsx +++ b/neetbox/frontend/src/pages/console/overview.tsx @@ -6,5 +6,5 @@ export default function Overview() { // const { isLoading, data, error } = useAPI("/status/" + projectName); // if (!data) return
Loading...
; // console.info({ isLoading, data }); - return
Overview
; + return
Overview WIP
; } From 5e2089509dce2be8e4e1414628b84b9b376009d3 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 21:37:09 +0800 Subject: [PATCH 010/114] fix: ws in dev mode --- neetbox/frontend/src/services/api.ts | 2 +- neetbox/frontend/vite.config.ts | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/neetbox/frontend/src/services/api.ts b/neetbox/frontend/src/services/api.ts index 230130ee..3c6da4cc 100644 --- a/neetbox/frontend/src/services/api.ts +++ b/neetbox/frontend/src/services/api.ts @@ -2,7 +2,7 @@ import useSWR from "swr"; export const API_BASEURL = "/web"; export const WEBSOCKET_URL = import.meta.env.DEV - ? "ws://localhost:5001" + ? `ws://${location.host}/ws/` : `ws://${location.hostname}:${Number(location.port) + 1}`; async function fetcher(url: string) { diff --git a/neetbox/frontend/vite.config.ts b/neetbox/frontend/vite.config.ts index fdbe853a..7365c945 100644 --- a/neetbox/frontend/vite.config.ts +++ b/neetbox/frontend/vite.config.ts @@ -2,6 +2,8 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import SemiPlugin from "vite-plugin-semi-theme"; +const server = new URL('http://127.0.0.1:5000'); + // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), SemiPlugin({ @@ -10,14 +12,15 @@ export default defineConfig({ server: { proxy: { '/web/': { - target: 'http://127.0.0.1:5000', + target: server.href, changeOrigin: true, // rewrite: (path) => path.replace(/^\/api\//, ''), }, '/ws/': { - target: 'http://127.0.0.1:5001', + target: `ws://${server.host}:${(+server.port) + 1}`, changeOrigin: true, rewrite: (path) => path.replace(/^\/ws\//, ''), + ws: true, } } }, From 12bba6469b7a69155eec5eced9504bdf043b500e Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 21:45:48 +0800 Subject: [PATCH 011/114] refactor: dashboard --- .../dashboard/project/hardware/cpugraph.tsx | 61 ++++++++++++++ .../dashboard/project/hardware/index.tsx | 19 +++++ .../dashboard/project/{ => logs}/logs.css | 0 .../dashboard/project/{ => logs}/logs.tsx | 2 +- neetbox/frontend/src/components/echarts.tsx | 2 +- .../src/pages/console/proejctDashboard.tsx | 81 +------------------ 6 files changed, 85 insertions(+), 80 deletions(-) create mode 100644 neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx create mode 100644 neetbox/frontend/src/components/dashboard/project/hardware/index.tsx rename neetbox/frontend/src/components/dashboard/project/{ => logs}/logs.css (100%) rename neetbox/frontend/src/components/dashboard/project/{ => logs}/logs.tsx (96%) diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx new file mode 100644 index 00000000..405385a5 --- /dev/null +++ b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx @@ -0,0 +1,61 @@ +import { useMemo } from "react"; +import { ECharts } from "../../../echarts"; +import { ProjectStatus } from "../../../../services/projects"; + +export const CPUGraph = ({ + hardwareData, +}: { + hardwareData: Array; +}) => { + const cpus = hardwareData[0].value.cpus; + const initialOption = () => { + return { + animation: false, + tooltip: { + trigger: "axis", + }, + legend: { + data: cpus.map((cpu) => `CPU${cpu.id}`), + }, + xAxis: { + type: "time", + }, + yAxis: { + type: "value", + max: cpus.length * 100, + }, + series: [], + } as echarts.EChartsOption; + }; + + const updatingOption = useMemo(() => { + const latestTime = hardwareData[hardwareData.length - 1].timestamp; + const newOption = { + series: cpus.map((cpu) => ({ + name: `CPU${cpu.id}`, + type: "line", + stack: "cpu", + areaStyle: {}, + symbol: null, + data: hardwareData.map((x) => [ + x.timestamp * 1000, + x.value.cpus[cpu.id].percent, + ]), + })), + xAxis: { + min: (latestTime - 60) * 1000, + max: latestTime * 1000, + data: new Array(10).fill(0).map((x, i) => i), + }, + } as echarts.EChartsOption; + return newOption; + }, [hardwareData]); + + return ( + + ); +}; diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx new file mode 100644 index 00000000..5012979d --- /dev/null +++ b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx @@ -0,0 +1,19 @@ +import { Typography } from "@douyinfe/semi-ui"; +import { ProjectStatus } from "../../../../services/projects"; +import { CPUGraph } from "./cpugraph"; + +export function Hardware({ + hardwareData, +}: { + hardwareData: Array; +}) { + return ( +
+ {hardwareData.every((x) => x.value.cpus) ? ( + + ) : ( + No CPU Info + )} +
+ ); +} diff --git a/neetbox/frontend/src/components/dashboard/project/logs.css b/neetbox/frontend/src/components/dashboard/project/logs/logs.css similarity index 100% rename from neetbox/frontend/src/components/dashboard/project/logs.css rename to neetbox/frontend/src/components/dashboard/project/logs/logs.css diff --git a/neetbox/frontend/src/components/dashboard/project/logs.tsx b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx similarity index 96% rename from neetbox/frontend/src/components/dashboard/project/logs.tsx rename to neetbox/frontend/src/components/dashboard/project/logs/logs.tsx index 497bd750..1d8265ec 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs.tsx +++ b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from "react"; -import { LogData, useProjectLogs } from "../../../services/projects"; +import { LogData, useProjectLogs } from "../../../../services/projects"; import "./logs.css"; interface Props { diff --git a/neetbox/frontend/src/components/echarts.tsx b/neetbox/frontend/src/components/echarts.tsx index 99a44234..60aa9f9b 100644 --- a/neetbox/frontend/src/components/echarts.tsx +++ b/neetbox/frontend/src/components/echarts.tsx @@ -12,7 +12,7 @@ export const ECharts = (props: EChartsProps) => { const chartContainerRef = useRef(null); const chartRef = useRef(null!); const [echartsModule, setEchartsModule] = useState( - null + null, ); useEffect(() => { diff --git a/neetbox/frontend/src/pages/console/proejctDashboard.tsx b/neetbox/frontend/src/pages/console/proejctDashboard.tsx index e6b0d528..90e18a0e 100644 --- a/neetbox/frontend/src/pages/console/proejctDashboard.tsx +++ b/neetbox/frontend/src/pages/console/proejctDashboard.tsx @@ -1,13 +1,12 @@ import { useParams } from "react-router-dom"; import { createContext, useMemo } from "react"; -import * as echarts from "echarts"; import { Typography } from "@douyinfe/semi-ui"; import PlatformProps from "../../components/dashboard/project/platformProps"; -import { ECharts } from "../../components/echarts"; -import { ProjectStatus, useProjectStatus } from "../../services/projects"; -import { Logs } from "../../components/dashboard/project/logs"; +import { useProjectStatus } from "../../services/projects"; +import { Logs } from "../../components/dashboard/project/logs/logs"; import { Actions } from "../../components/dashboard/project/actions"; import Loading from "../../components/loading"; +import { Hardware } from "../../components/dashboard/project/hardware"; export const ProjectContext = createContext<{ projectName: string } | null>( null, @@ -56,77 +55,3 @@ function ProjectDashboard() { ); } - -function Hardware({ - hardwareData, -}: { - hardwareData: Array; -}) { - return ( -
- {hardwareData.every((x) => x.value.cpus) ? ( - - ) : ( - No CPU Info - )} -
- ); -} - -const CPUGraph = ({ - hardwareData, -}: { - hardwareData: Array; -}) => { - const cpus = hardwareData[0].value.cpus; - const initialOption = () => { - return { - animation: false, - tooltip: { - trigger: "axis", - }, - legend: { - data: cpus.map((cpu) => `CPU${cpu.id}`), - }, - xAxis: { - type: "time", - }, - yAxis: { - type: "value", - max: cpus.length * 100, - }, - series: [], - } as echarts.EChartsOption; - }; - - const updatingOption = useMemo(() => { - const latestTime = hardwareData[hardwareData.length - 1].timestamp; - const newOption = { - series: cpus.map((cpu) => ({ - name: `CPU${cpu.id}`, - type: "line", - stack: "cpu", - areaStyle: {}, - symbol: null, - data: hardwareData.map((x) => [ - x.timestamp * 1000, - x.value.cpus[cpu.id].percent, - ]), - })), - xAxis: { - min: (latestTime - 60) * 1000, - max: latestTime * 1000, - data: new Array(10).fill(0).map((x, i) => i), - }, - } as echarts.EChartsOption; - return newOption; - }, [hardwareData]); - - return ( - - ); -}; From 742f6bc3622ecb4c0f04548c1817b491e2fe4386 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 22:24:20 +0800 Subject: [PATCH 012/114] fix: dashboard margins --- neetbox/frontend/.gitignore | 1 - .../src/components/dashboard/project/actions.tsx | 6 ++++-- .../components/dashboard/project/logs/logs.tsx | 1 - neetbox/frontend/src/components/sectionTitle.tsx | 15 +++++++++++++++ .../src/pages/console/proejctDashboard.tsx | 16 ++++++++++------ 5 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 neetbox/frontend/src/components/sectionTitle.tsx diff --git a/neetbox/frontend/.gitignore b/neetbox/frontend/.gitignore index a547bf36..019e1dca 100644 --- a/neetbox/frontend/.gitignore +++ b/neetbox/frontend/.gitignore @@ -1,5 +1,4 @@ # Logs -logs *.log npm-debug.log* yarn-debug.log* diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index 6bc840e8..417e0678 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -19,7 +19,7 @@ export function Actions({ actions }: Props) { const [blocking, setBlocking] = useState(false); const actionList = Object.entries(actions?.value ?? {}); return ( - + {actionList.length ? ( actionList.map(([actionName, actionOptions]) => ( (
- + {name} {options.description && (
@@ -101,6 +101,8 @@ export function ActionItem({ ; } diff --git a/neetbox/frontend/src/main.tsx b/neetbox/frontend/src/main.tsx index 84f71bb4..c657ffe3 100644 --- a/neetbox/frontend/src/main.tsx +++ b/neetbox/frontend/src/main.tsx @@ -6,6 +6,7 @@ import LoginPage from "./pages/login"; import "./index.css"; import Console, { consoleRoutes } from "./pages/console"; import { startBackgroundTasks } from "./services/projects"; +import { ThemeContextProvider } from "./components/themeSwitcher"; const router = createBrowserRouter([ { @@ -36,8 +37,10 @@ function ServiceProvider({ children }: PropsWithChildren) { ReactDOM.createRoot(document.getElementById("root")!).render( - - - - + + + + + + , ); From 6389edea80404e68132484e113589edf2b67b0b3 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 22:30:27 +0800 Subject: [PATCH 014/114] fix: set updatingOption on echarts init --- neetbox/frontend/src/components/echarts.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/neetbox/frontend/src/components/echarts.tsx b/neetbox/frontend/src/components/echarts.tsx index 0a5d91fc..78a643b4 100644 --- a/neetbox/frontend/src/components/echarts.tsx +++ b/neetbox/frontend/src/components/echarts.tsx @@ -29,6 +29,7 @@ export const ECharts = (props: EChartsProps) => { ); chart.setOption(props.initialOption()); + chart.setOption(props.updatingOption); chartRef.current = chart; const handleResize = () => { From 32159182a1f705ae47a81cc8e412125144214ec8 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 23:12:14 +0800 Subject: [PATCH 015/114] feat: gpu graph --- .../dashboard/project/hardware/cpugraph.tsx | 22 ++++- .../dashboard/project/hardware/gpugraph.tsx | 93 +++++++++++++++++++ .../dashboard/project/hardware/index.tsx | 8 ++ .../dashboard/project/logs/logs.tsx | 2 +- neetbox/frontend/src/components/echarts.tsx | 3 +- 5 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx index c6fb34e2..790c2975 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx @@ -10,20 +10,34 @@ export const CPUGraph = ({ const cpus = hardwareData[0].value.cpus; const initialOption = () => { return { - backgroundColor: 'transparent', + backgroundColor: "transparent", animation: false, tooltip: { trigger: "axis", }, - legend: { - data: cpus.map((cpu) => `CPU${cpu.id}`), + grid: { + top: 30, + bottom: 30, }, + title: { + text: `CPU Load (${cpus.length} threads)`, + left: "center", + textStyle: { + fontSize: 14, + }, + }, + // legend: { + // data: cpus.map((cpu) => `CPU${cpu.id}`), + // }, xAxis: { type: "time", }, yAxis: { type: "value", max: cpus.length * 100, + axisLabel: { + formatter: (x) => x + " %", + }, }, series: [], } as echarts.EChartsOption; @@ -56,7 +70,7 @@ export const CPUGraph = ({ ); }; diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx new file mode 100644 index 00000000..56b3f66e --- /dev/null +++ b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx @@ -0,0 +1,93 @@ +import { useMemo } from "react"; +import { ECharts } from "../../../echarts"; +import { ProjectStatus } from "../../../../services/projects"; + +export const GPUGraph = ({ + hardwareData, + gpuId, +}: { + hardwareData: Array; + gpuId: number; +}) => { + const gpus = hardwareData[0].value.gpus; + const initialOption = () => { + return { + backgroundColor: "transparent", + animation: false, + tooltip: { + trigger: "axis", + }, + grid: { + top: 30, + bottom: 30, + }, + legend: { + data: [`GPU${gpuId} Load`, `GPU${gpuId} Memory`], + }, + xAxis: { + type: "time", + }, + yAxis: [ + { + type: "value", + max: 100, + axisLabel: { + formatter: (x) => x + " %", + }, + }, + { + type: "value", + position: "right", + splitLine: null, + axisLabel: { + formatter: (x) => x + " MB", + }, + max: gpus[gpuId].memoryTotal, + }, + ], + series: [], + } as echarts.EChartsOption; + }; + + const updatingOption = useMemo(() => { + const latestTime = hardwareData[hardwareData.length - 1].timestamp; + const newOption = { + series: [ + { + name: `GPU${gpuId} Load`, + type: "line", + areaStyle: null, + symbol: null, + data: hardwareData.map((x) => [ + x.timestamp * 1000, + x.value.gpus[gpuId].load * 100, + ]), + }, + { + name: `GPU${gpuId} Memory`, + type: "line", + areaStyle: {}, + symbol: null, + yAxisIndex: 1, + data: hardwareData.map((x) => [ + x.timestamp * 1000, + x.value.gpus[gpuId].memoryUsed, + ]), + }, + ], + xAxis: { + min: (latestTime - 60) * 1000, + max: latestTime * 1000, + }, + } as echarts.EChartsOption; + return newOption; + }, [hardwareData]); + + return ( + + ); +}; diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx index 5012979d..683d6c56 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx @@ -1,6 +1,7 @@ import { Typography } from "@douyinfe/semi-ui"; import { ProjectStatus } from "../../../../services/projects"; import { CPUGraph } from "./cpugraph"; +import { GPUGraph } from "./gpugraph"; export function Hardware({ hardwareData, @@ -14,6 +15,13 @@ export function Hardware({ ) : ( No CPU Info )} + {hardwareData.every((x) => x.value.gpus) ? ( + hardwareData[0].value.gpus.map((_, i) => ( + + )) + ) : ( + No GPU Info + )}
); } diff --git a/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx index 4a3156a2..897d45e7 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx +++ b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx @@ -17,7 +17,7 @@ function AutoScrolling({ const dom = containerRef.current; if (dom) { setFollowing( - Math.abs(dom.scrollHeight - dom.clientHeight - dom.scrollTop) < 5 + Math.abs(dom.scrollHeight - dom.clientHeight - dom.scrollTop) < 30, ); } setRenderingElement(children); diff --git a/neetbox/frontend/src/components/echarts.tsx b/neetbox/frontend/src/components/echarts.tsx index 78a643b4..7690fb20 100644 --- a/neetbox/frontend/src/components/echarts.tsx +++ b/neetbox/frontend/src/components/echarts.tsx @@ -26,9 +26,10 @@ export const ECharts = (props: EChartsProps) => { const chart = echartsModule.init( chartContainerRef.current, darkMode ? "dark" : null, + // { renderer: "svg" }, ); - chart.setOption(props.initialOption()); + chart.setOption(props.initialOption(), false, true); chart.setOption(props.updatingOption); chartRef.current = chart; From 8dd5e20495866491b76c6a83442faf137694a288 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 23:16:06 +0800 Subject: [PATCH 016/114] fix: actions wrap --- neetbox/frontend/src/components/dashboard/project/actions.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index 417e0678..3f265554 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -19,7 +19,7 @@ export function Actions({ actions }: Props) { const [blocking, setBlocking] = useState(false); const actionList = Object.entries(actions?.value ?? {}); return ( - + {actionList.length ? ( actionList.map(([actionName, actionOptions]) => ( (
- + {name} {options.description && (
From d9faefadf95782bd1a3656123cf72ba07dd4f797 Mon Sep 17 00:00:00 2001 From: lideming Date: Mon, 27 Nov 2023 23:27:50 +0800 Subject: [PATCH 017/114] feat: ram graph --- .../dashboard/project/hardware/cpugraph.tsx | 2 +- .../dashboard/project/hardware/gpugraph.tsx | 6 +- .../dashboard/project/hardware/index.tsx | 16 +++-- .../dashboard/project/hardware/ramgraph.tsx | 71 +++++++++++++++++++ 4 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx index 790c2975..f7d7dab4 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx @@ -23,7 +23,7 @@ export const CPUGraph = ({ text: `CPU Load (${cpus.length} threads)`, left: "center", textStyle: { - fontSize: 14, + fontSize: 12, }, }, // legend: { diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx index 56b3f66e..663e3aac 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx @@ -40,9 +40,9 @@ export const GPUGraph = ({ position: "right", splitLine: null, axisLabel: { - formatter: (x) => x + " MB", + formatter: (x) => x.toFixed(1) + " GB", }, - max: gpus[gpuId].memoryTotal, + max: gpus[gpuId].memoryTotal / 1024, }, ], series: [], @@ -71,7 +71,7 @@ export const GPUGraph = ({ yAxisIndex: 1, data: hardwareData.map((x) => [ x.timestamp * 1000, - x.value.gpus[gpuId].memoryUsed, + x.value.gpus[gpuId].memoryUsed / 1024, ]), }, ], diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx index 683d6c56..98d11ab8 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx @@ -2,6 +2,7 @@ import { Typography } from "@douyinfe/semi-ui"; import { ProjectStatus } from "../../../../services/projects"; import { CPUGraph } from "./cpugraph"; import { GPUGraph } from "./gpugraph"; +import { RAMGraph } from "./ramgraph"; export function Hardware({ hardwareData, @@ -10,11 +11,6 @@ export function Hardware({ }) { return (
- {hardwareData.every((x) => x.value.cpus) ? ( - - ) : ( - No CPU Info - )} {hardwareData.every((x) => x.value.gpus) ? ( hardwareData[0].value.gpus.map((_, i) => ( @@ -22,6 +18,16 @@ export function Hardware({ ) : ( No GPU Info )} + {hardwareData.every((x) => x.value.cpus) ? ( + + ) : ( + No CPU Info + )} + {hardwareData.every((x) => x.value.ram) ? ( + + ) : ( + No RAM Info + )}
); } diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx new file mode 100644 index 00000000..cc966f33 --- /dev/null +++ b/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx @@ -0,0 +1,71 @@ +import { useMemo } from "react"; +import { ECharts } from "../../../echarts"; +import { ProjectStatus } from "../../../../services/projects"; + +export const RAMGraph = ({ + hardwareData, +}: { + hardwareData: Array; +}) => { + const initialOption = () => { + return { + backgroundColor: "transparent", + animation: false, + tooltip: { + trigger: "axis", + }, + grid: { + top: 30, + bottom: 30, + }, + legend: { + data: [`RAM Used`], + }, + xAxis: { + type: "time", + }, + yAxis: [ + { + type: "value", + position: 'right', + axisLabel: { + formatter: (x) => x.toFixed(1) + " GB", + }, + max: hardwareData[0].value.ram.total, + }, + ], + series: [], + } as echarts.EChartsOption; + }; + + const updatingOption = useMemo(() => { + const latestTime = hardwareData[hardwareData.length - 1].timestamp; + const newOption = { + series: [ + { + name: `RAM Used`, + type: "line", + areaStyle: {}, + symbol: null, + data: hardwareData.map((x) => [ + x.timestamp * 1000, + x.value.ram.used, + ]), + }, + ], + xAxis: { + min: (latestTime - 60) * 1000, + max: latestTime * 1000, + }, + } as echarts.EChartsOption; + return newOption; + }, [hardwareData]); + + return ( + + ); +}; From 2761256c7ccbabeaf7c9936ac5fad74be6b2b890 Mon Sep 17 00:00:00 2001 From: lideming Date: Tue, 28 Nov 2023 01:15:36 +0800 Subject: [PATCH 018/114] feat: adjust graphs title --- .../dashboard/project/hardware/cpugraph.tsx | 3 +-- .../dashboard/project/hardware/gpugraph.tsx | 12 +++++++++--- .../dashboard/project/hardware/ramgraph.tsx | 13 ++++++++----- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx index f7d7dab4..c7e9831f 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx @@ -20,8 +20,7 @@ export const CPUGraph = ({ bottom: 30, }, title: { - text: `CPU Load (${cpus.length} threads)`, - left: "center", + text: `CPU (${cpus.length} threads)`, textStyle: { fontSize: 12, }, diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx index 663e3aac..22796a9d 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx @@ -21,8 +21,14 @@ export const GPUGraph = ({ top: 30, bottom: 30, }, + title: { + text: `GPU${gpuId}: ${gpus[gpuId].name}`, + textStyle: { + fontSize: 12, + }, + }, legend: { - data: [`GPU${gpuId} Load`, `GPU${gpuId} Memory`], + data: [`Load`, `Memory`], }, xAxis: { type: "time", @@ -54,7 +60,7 @@ export const GPUGraph = ({ const newOption = { series: [ { - name: `GPU${gpuId} Load`, + name: `Load`, type: "line", areaStyle: null, symbol: null, @@ -64,7 +70,7 @@ export const GPUGraph = ({ ]), }, { - name: `GPU${gpuId} Memory`, + name: `Memory`, type: "line", areaStyle: {}, symbol: null, diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx index cc966f33..c4d1ad85 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx @@ -14,6 +14,12 @@ export const RAMGraph = ({ tooltip: { trigger: "axis", }, + title: { + text: `RAM`, + textStyle: { + fontSize: 12, + }, + }, grid: { top: 30, bottom: 30, @@ -27,7 +33,7 @@ export const RAMGraph = ({ yAxis: [ { type: "value", - position: 'right', + position: "right", axisLabel: { formatter: (x) => x.toFixed(1) + " GB", }, @@ -47,10 +53,7 @@ export const RAMGraph = ({ type: "line", areaStyle: {}, symbol: null, - data: hardwareData.map((x) => [ - x.timestamp * 1000, - x.value.ram.used, - ]), + data: hardwareData.map((x) => [x.timestamp * 1000, x.value.ram.used]), }, ], xAxis: { From 3f06d1ae593d056c008bed85bf0af4eb73218b3d Mon Sep 17 00:00:00 2001 From: lideming Date: Tue, 28 Nov 2023 19:57:54 +0800 Subject: [PATCH 019/114] test: add snake game --- .../dashboard/project/logs/logs.css | 1 + tests/client/snake.py | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 tests/client/snake.py diff --git a/neetbox/frontend/src/components/dashboard/project/logs/logs.css b/neetbox/frontend/src/components/dashboard/project/logs/logs.css index 4ef4bbdf..1dac9f10 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs/logs.css +++ b/neetbox/frontend/src/components/dashboard/project/logs/logs.css @@ -1,6 +1,7 @@ .log-item { margin-bottom: 5px; font-family: "Courier New", Courier, monospace; + white-space: pre-wrap; font-size: 13px; .log-tag { diff --git a/tests/client/snake.py b/tests/client/snake.py new file mode 100644 index 00000000..6cb02299 --- /dev/null +++ b/tests/client/snake.py @@ -0,0 +1,131 @@ +from random import random +from threading import Thread +from time import sleep + +from neetbox.daemon import action +from neetbox.logging import logger +from neetbox.pipeline import listen, watch + +EMPTY = " " +BODY = "o" +HEAD = "O" +FOOD = "x" + +MAP_WIDTH, MAP_HEIGHT = 20, 10 + +cur_direction = (1, 0) + +game_running = False + +logger.info("starting") + + +@action(blocking=False) +def start_game(): + def thread(): + global game_running + if game_running: + logger.err("game already running") + return + game_running = True + try: + game() + except Exception as e: + logger.err(e) + game_running = False + + Thread(target=thread).start() + + +@action() +def left(): + global cur_direction + cur_direction = (-1, 0) + + +@action() +def down(): + global cur_direction + cur_direction = (0, 1) + + +@action() +def up(): + global cur_direction + cur_direction = (0, -1) + + +@action() +def right(): + global cur_direction + cur_direction = (1, 0) + + +def game(): + global cur_direction + cur_direction = (1, 0) + gamemap = [[EMPTY for _ in range(MAP_WIDTH)] for _ in range(MAP_HEIGHT)] + bodies = [] + cur_head = 3, 3 + + def main(): + logger.info("===================snake game===================") + put_head((3, 3)) + put_head((4, 3)) + put_head((5, 3)) + place_food() + while True: + print_map() + logger.info(f"head = {cur_head}, direction = {cur_direction}") + sleep(1) + next_pos = (cur_head[0] + cur_direction[0], cur_head[1] + cur_direction[1]) + next_thing = get_map(next_pos) + if next_thing in [BODY, None]: + logger.err("GAME OVER") + break + + put_head(next_pos) + if next_thing == FOOD: + place_food() + else: + remove_tail() + + def put_head(pos): + nonlocal cur_head + set_map(cur_head, BODY) + set_map(pos, HEAD) + cur_head = pos + bodies.append(pos) + + def remove_tail(): + set_map(bodies[0], EMPTY) + bodies.remove(bodies[0]) + + def place_food(): + while True: + x, y = int(random() * MAP_WIDTH), int(random() * MAP_HEIGHT) + if get_map((x, y)) != EMPTY: + continue + set_map((x, y), FOOD) + break + + def get_map(pos): + x, y = pos + return gamemap[y][x] if (0 <= x < MAP_WIDTH) and (0 <= y < MAP_HEIGHT) else None + + def set_map(pos, val): + x, y = pos + gamemap[y][x] = val + + def print_map(): + logger.info("+" + " ".join("-" * MAP_WIDTH) + "+") + for y in range(MAP_HEIGHT): + logger.info("|" + " ".join(gamemap[y]) + "|") + logger.info("+" + " ".join("-" * MAP_WIDTH) + "+") + + main() + + +while True: + sleep(1000) + game_running = True From ea4fd238c06b7f3c920c85a34569326138d624c5 Mon Sep 17 00:00:00 2001 From: lideming Date: Tue, 28 Nov 2023 23:13:51 +0800 Subject: [PATCH 020/114] fixed ws not connection on action agent register new actions --- neetbox/daemon/client/_action_agent.py | 1 + tests/client/snake.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/neetbox/daemon/client/_action_agent.py b/neetbox/daemon/client/_action_agent.py index 561269f4..00a50081 100644 --- a/neetbox/daemon/client/_action_agent.py +++ b/neetbox/daemon/client/_action_agent.py @@ -105,6 +105,7 @@ def _update_action_dict(): return _NeetActionManager.get_action_dict() def register(name: Optional[str] = None, description: str = None, blocking: bool = False): + connection._init_ws() return functools.partial( _NeetActionManager._register, name=name, description=description, blocking=blocking ) diff --git a/tests/client/snake.py b/tests/client/snake.py index 6cb02299..18e3b4bc 100644 --- a/tests/client/snake.py +++ b/tests/client/snake.py @@ -17,7 +17,7 @@ game_running = False -logger.info("starting") +# logger.info("starting") @action(blocking=False) From 55d4f6a0b480d821aae871b97687584e9d040b83 Mon Sep 17 00:00:00 2001 From: lideming Date: Tue, 28 Nov 2023 23:28:49 +0800 Subject: [PATCH 021/114] fix: non blocking actions --- .../components/dashboard/project/actions.tsx | 8 ++--- tests/client/snake.py | 30 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index 3f265554..2849ead4 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -56,13 +56,13 @@ export function ActionItem({ setBlocking, }: ActionItemProps) { const [args, setArgs] = useState>({}); - const [currentBlocking, setCurrentBlocking] = useState(false); + const [running, setCurrentBlocking] = useState(false); const { projectName } = useContext(ProjectContext)!; const handleRun = () => { - setBlocking(true); + if (options.blocking) setBlocking(true); setCurrentBlocking(true); getProject(projectName).sendAction(name, args, () => { - setBlocking(false); + if (options.blocking) setBlocking(false); setCurrentBlocking(false); }); }; @@ -112,7 +112,7 @@ export function ActionItem({ ); return ( - diff --git a/tests/client/snake.py b/tests/client/snake.py index 18e3b4bc..268948d3 100644 --- a/tests/client/snake.py +++ b/tests/client/snake.py @@ -22,19 +22,16 @@ @action(blocking=False) def start_game(): - def thread(): - global game_running - if game_running: - logger.err("game already running") - return - game_running = True - try: - game() - except Exception as e: - logger.err(e) - game_running = False - - Thread(target=thread).start() + global game_running + if game_running: + logger.err("game already running") + return + game_running = True + try: + game() + except Exception as e: + logger.err(e) + game_running = False @action() @@ -82,6 +79,7 @@ def main(): next_thing = get_map(next_pos) if next_thing in [BODY, None]: logger.err("GAME OVER") + logger.info(f"SCORE = {len(bodies)}") break put_head(next_pos) @@ -118,10 +116,10 @@ def set_map(pos, val): gamemap[y][x] = val def print_map(): - logger.info("+" + " ".join("-" * MAP_WIDTH) + "+") + logger.info("+ " + " ".join("-" * MAP_WIDTH) + " +") for y in range(MAP_HEIGHT): - logger.info("|" + " ".join(gamemap[y]) + "|") - logger.info("+" + " ".join("-" * MAP_WIDTH) + "+") + logger.info("| " + " ".join(gamemap[y]) + " |") + logger.info("+ " + " ".join("-" * MAP_WIDTH) + " +") main() From 2787e17b388bd511944593588032ff48890acbe4 Mon Sep 17 00:00:00 2001 From: lideming Date: Wed, 29 Nov 2023 00:14:08 +0800 Subject: [PATCH 022/114] feat: actions result --- .../components/dashboard/project/actions.tsx | 117 +++++++++++------- neetbox/frontend/src/services/projects.ts | 7 +- tests/client/test.py | 6 + 3 files changed, 86 insertions(+), 44 deletions(-) diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index 2849ead4..94876173 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -1,5 +1,6 @@ import { Button, + Checkbox, Col, Input, Popover, @@ -55,60 +56,92 @@ export function ActionItem({ blocking, setBlocking, }: ActionItemProps) { - const [args, setArgs] = useState>({}); + const [args, setArgs] = useState>(() => + Object.fromEntries( + Object.entries(options.args).map(([name, type]) => [ + name, + type == "str" ? '""' : type == "bool" ? "False" : "", + ]) + ) + ); const [running, setCurrentBlocking] = useState(false); + const [result, setResult] = useState(null); const { projectName } = useContext(ProjectContext)!; const handleRun = () => { if (options.blocking) setBlocking(true); setCurrentBlocking(true); - getProject(projectName).sendAction(name, args, () => { - if (options.blocking) setBlocking(false); - setCurrentBlocking(false); - }); + getProject(projectName).sendAction( + name, + args, + ({ error: err, result: res }) => { + if (options.blocking) setBlocking(false); + setCurrentBlocking(false); + setResult(err ? `error:\n${err}` : `result:\n${JSON.stringify(res)}`); + } + ); }; const renderContent = () => ( -
- - {name} - {options.description && ( -
- {options.description} -
- )} - {Object.entries(options.args).map(([argName, argType]) => ( - - - {argName} - - + + {name} + {options.description && ( +
+ {options.description} +
+ )} + {Object.entries(options.args).map(([argName, argType]) => ( + + + {argName} + + + {argType == "bool" ? ( + + setArgs({ + ...args, + [argName]: args[argName] == "True" ? "False" : "True", + }) + } + > + {args[argName]} + + ) : ( setArgs({ ...args, [argName]: val })} /> - - - ({argType}) - - - ))} - -
-
+ )} + + + ({argType}) + + + ))} + + {result && ( +
{result}
+ )} + ); return ( diff --git a/neetbox/frontend/src/services/projects.ts b/neetbox/frontend/src/services/projects.ts index 0ecfba7b..2445dfdf 100644 --- a/neetbox/frontend/src/services/projects.ts +++ b/neetbox/frontend/src/services/projects.ts @@ -101,7 +101,7 @@ export class Project { sendAction( action: string, args: Record, - onReply?: () => void, + onReply?: (result: any) => void ) { this.wsClient.send( { @@ -111,7 +111,10 @@ export class Project { args, }, }, - onReply, + onReply && + ((msg) => { + onReply(msg.payload); + }) ); } } diff --git a/tests/client/test.py b/tests/client/test.py index 128917b8..31b2e1fe 100644 --- a/tests/client/test.py +++ b/tests/client/test.py @@ -39,6 +39,12 @@ def action_1(text: str): logger.log(f"action 1 triggered. text = {text}") +@action() +def action_bool(enable: bool): + logger.info(f"action_bool triggered. enable = {enable}") + return {"enable": enable} + + val = 0 From 8f3e513b9c07b78c51f5c0e8686ceebe8bfa5e60 Mon Sep 17 00:00:00 2001 From: lideming Date: Wed, 29 Nov 2023 09:55:58 +0800 Subject: [PATCH 023/114] refactor: frontend --- .../components/dashboard/project/actions.tsx | 9 +++-- .../dashboard/project/hardware/index.tsx | 18 +++++++--- .../dashboard/project/logs/logs.tsx | 3 +- neetbox/frontend/src/components/echarts.tsx | 6 ++-- .../frontend/src/components/themeSwitcher.tsx | 34 ++++++------------- neetbox/frontend/src/hooks/useProject.ts | 14 ++++++++ neetbox/frontend/src/hooks/useTheme.tsx | 10 ++++++ neetbox/frontend/src/main.tsx | 12 ++----- .../src/pages/console/proejctDashboard.tsx | 6 ++-- neetbox/frontend/src/services/projects.ts | 23 +++++-------- .../frontend/src/services/serviceProvider.tsx | 10 ++++++ tests/client/test.py | 23 ++++++++----- 12 files changed, 97 insertions(+), 71 deletions(-) create mode 100644 neetbox/frontend/src/hooks/useProject.ts create mode 100644 neetbox/frontend/src/hooks/useTheme.tsx create mode 100644 neetbox/frontend/src/services/serviceProvider.tsx diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index 94876173..fbe79132 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -24,6 +24,7 @@ export function Actions({ actions }: Props) { {actionList.length ? ( actionList.map(([actionName, actionOptions]) => ( - {argName} + + {argName} + {argType == "bool" ? ( @@ -125,7 +128,9 @@ export function ActionItem({ )} - ({argType}) + + ({argType}) + ))} diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx index 98d11ab8..120ed220 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx @@ -11,23 +11,31 @@ export function Hardware({ }) { return (
- {hardwareData.every((x) => x.value.gpus) ? ( + {hardwareData.every((x) => x.value.gpus.length) ? ( hardwareData[0].value.gpus.map((_, i) => ( )) ) : ( - No GPU Info + )} - {hardwareData.every((x) => x.value.cpus) ? ( + {hardwareData.every((x) => x.value.cpus.length) ? ( ) : ( - No CPU Info + )} {hardwareData.every((x) => x.value.ram) ? ( ) : ( - No RAM Info + )}
); } + +function NoInfoLabel({ text }: { text: string }) { + return ( + + {text} + + ); +} diff --git a/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx index 897d45e7..f3abdbbb 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx +++ b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from "react"; -import { LogData, useProjectLogs } from "../../../../services/projects"; +import { LogData } from "../../../../services/projects"; import "./logs.css"; +import { useProjectLogs } from "../../../../hooks/useProject"; interface Props { projectName: string; diff --git a/neetbox/frontend/src/components/echarts.tsx b/neetbox/frontend/src/components/echarts.tsx index 7690fb20..3774e45d 100644 --- a/neetbox/frontend/src/components/echarts.tsx +++ b/neetbox/frontend/src/components/echarts.tsx @@ -1,7 +1,7 @@ import { useRef, useEffect, HTMLAttributes, useState } from "react"; import type * as echarts from "echarts"; +import { useTheme } from "../hooks/useTheme"; import Loading from "./loading"; -import { useTheme } from "./themeSwitcher"; export interface EChartsProps { initialOption: () => echarts.EChartsOption; @@ -13,7 +13,7 @@ export const ECharts = (props: EChartsProps) => { const chartContainerRef = useRef(null); const chartRef = useRef(null!); const [echartsModule, setEchartsModule] = useState( - null, + null ); const { darkMode } = useTheme(); @@ -25,7 +25,7 @@ export const ECharts = (props: EChartsProps) => { if (echartsModule) { const chart = echartsModule.init( chartContainerRef.current, - darkMode ? "dark" : null, + darkMode ? "dark" : null // { renderer: "svg" }, ); diff --git a/neetbox/frontend/src/components/themeSwitcher.tsx b/neetbox/frontend/src/components/themeSwitcher.tsx index 3d2a7d75..1c93bf70 100644 --- a/neetbox/frontend/src/components/themeSwitcher.tsx +++ b/neetbox/frontend/src/components/themeSwitcher.tsx @@ -1,19 +1,13 @@ -import React, { - createContext, - useCallback, - useContext, - useEffect, - useState, -} from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { Button } from "@douyinfe/semi-ui"; +import { ThemeContext, useTheme } from "../hooks/useTheme"; -const Context = createContext<{ - darkMode: boolean; - setDarkMode: (val: boolean) => void; -}>(null!); - -export function useTheme() { - return useContext(Context); +export default function SwitchColorMode(): React.JSX.Element { + const { darkMode, setDarkMode } = useTheme(); + const switchMode = () => { + setDarkMode(!darkMode); + }; + return ; } export function ThemeContextProvider(props: React.PropsWithChildren) { @@ -38,16 +32,8 @@ export function ThemeContextProvider(props: React.PropsWithChildren) { }, [darkMode]); return ( - + {props.children} - + ); } - -export default function SwitchColorMode(): React.JSX.Element { - const { darkMode, setDarkMode } = useTheme(); - const switchMode = () => { - setDarkMode(!darkMode); - }; - return ; -} diff --git a/neetbox/frontend/src/hooks/useProject.ts b/neetbox/frontend/src/hooks/useProject.ts new file mode 100644 index 00000000..42e62d98 --- /dev/null +++ b/neetbox/frontend/src/hooks/useProject.ts @@ -0,0 +1,14 @@ +import { useAtom } from "jotai"; +import { getProject } from "../services/projects"; + +export function useProjectStatus(name: string) { + const project = getProject(name); + const [data] = useAtom(project.status.atom); + return data; +} + +export function useProjectLogs(name: string) { + const project = getProject(name); + const [data] = useAtom(project?.logs.atom); + return data; +} diff --git a/neetbox/frontend/src/hooks/useTheme.tsx b/neetbox/frontend/src/hooks/useTheme.tsx new file mode 100644 index 00000000..0d1dac99 --- /dev/null +++ b/neetbox/frontend/src/hooks/useTheme.tsx @@ -0,0 +1,10 @@ +import { createContext, useContext } from "react"; + +export const ThemeContext = createContext<{ + darkMode: boolean; + setDarkMode: (val: boolean) => void; +}>(null!); + +export function useTheme() { + return useContext(ThemeContext); +} diff --git a/neetbox/frontend/src/main.tsx b/neetbox/frontend/src/main.tsx index c657ffe3..a32b13e6 100644 --- a/neetbox/frontend/src/main.tsx +++ b/neetbox/frontend/src/main.tsx @@ -5,8 +5,8 @@ import AppLayout, { Home } from "./App"; import LoginPage from "./pages/login"; import "./index.css"; import Console, { consoleRoutes } from "./pages/console"; -import { startBackgroundTasks } from "./services/projects"; import { ThemeContextProvider } from "./components/themeSwitcher"; +import { ServiceProvider } from "./services/serviceProvider"; const router = createBrowserRouter([ { @@ -27,14 +27,6 @@ const router = createBrowserRouter([ }, ]); -function ServiceProvider({ children }: PropsWithChildren) { - useEffect(() => { - const tasks = startBackgroundTasks(); - return () => tasks.stop(); - }); - return children; -} - ReactDOM.createRoot(document.getElementById("root")!).render( @@ -42,5 +34,5 @@ ReactDOM.createRoot(document.getElementById("root")!).render( - , + ); diff --git a/neetbox/frontend/src/pages/console/proejctDashboard.tsx b/neetbox/frontend/src/pages/console/proejctDashboard.tsx index 1aaf6e32..e52e84d5 100644 --- a/neetbox/frontend/src/pages/console/proejctDashboard.tsx +++ b/neetbox/frontend/src/pages/console/proejctDashboard.tsx @@ -2,7 +2,7 @@ import { useParams } from "react-router-dom"; import { createContext, useMemo } from "react"; import { Divider, Typography } from "@douyinfe/semi-ui"; import PlatformProps from "../../components/dashboard/project/platformProps"; -import { useProjectStatus } from "../../services/projects"; +import { useProjectStatus } from "../../hooks/useProject"; import { Logs } from "../../components/dashboard/project/logs/logs"; import { Actions } from "../../components/dashboard/project/actions"; import Loading from "../../components/loading"; @@ -10,7 +10,7 @@ import { Hardware } from "../../components/dashboard/project/hardware"; import { SectionTitle } from "../../components/sectionTitle"; export const ProjectContext = createContext<{ projectName: string } | null>( - null, + null ); export default function ProjectDashboardButRecreateOnRouteChange() { @@ -29,7 +29,7 @@ function ProjectDashboard() { () => ({ projectName, }), - [projectName], + [projectName] ); return ( diff --git a/neetbox/frontend/src/services/projects.ts b/neetbox/frontend/src/services/projects.ts index 2445dfdf..0603a871 100644 --- a/neetbox/frontend/src/services/projects.ts +++ b/neetbox/frontend/src/services/projects.ts @@ -62,7 +62,6 @@ export interface LogData { } const projects = new Map(); -const nullProjectAtom = atom(null!); export class Project { wsClient: WsClient; @@ -89,7 +88,7 @@ export class Project { }); const projectData = { ...this.status.value }; projectData.current = data; - projectData.history = slideWindow(projectData.history, data, 60); + projectData.history = slideWindow(projectData.history, data, 70); this.status.value = projectData; }); } @@ -128,18 +127,6 @@ export function getProject(name: string) { return project; } -export function useProjectStatus(name: string) { - const project = getProject(name); - const [data] = useAtom(project?.status.atom ?? nullProjectAtom); - return data; -} - -export function useProjectLogs(name: string) { - const project = getProject(name); - const [data] = useAtom(project?.logs.atom); - return data; -} - export function startBackgroundTasks() { function updateAllProjectsData() { for (const project of projects.values()) { @@ -148,7 +135,13 @@ export function startBackgroundTasks() { } const timer = setInterval(updateAllProjectsData, 1000); return { - stop: () => clearInterval(timer), + dispose: () => { + clearInterval(timer); + for (const [name, project] of projects) { + projects.delete(name); + project.wsClient.ws.close(); + } + }, }; } diff --git a/neetbox/frontend/src/services/serviceProvider.tsx b/neetbox/frontend/src/services/serviceProvider.tsx new file mode 100644 index 00000000..2843a6db --- /dev/null +++ b/neetbox/frontend/src/services/serviceProvider.tsx @@ -0,0 +1,10 @@ +import { PropsWithChildren, useEffect } from "react"; +import { startBackgroundTasks } from "./projects"; + +export function ServiceProvider({ children }: PropsWithChildren) { + useEffect(() => { + const tasks = startBackgroundTasks(); + return () => tasks.dispose(); + }); + return children; +} diff --git a/tests/client/test.py b/tests/client/test.py index 31b2e1fe..c5e9dd4d 100644 --- a/tests/client/test.py +++ b/tests/client/test.py @@ -45,18 +45,18 @@ def action_bool(enable: bool): return {"enable": enable} -val = 0 +@action() +def action_very_long_name(arg_with_very_long_long_name: int): + return {"very_long_long_result_key": arg_with_very_long_long_name} -def def_plus_1(): +def def_plus_1(val): @action(name="plus1", description=f"val={val}") def plus_1(): - global val - val += 1 - def_plus_1() + def_plus_1(val + 1) -def_plus_1() +def_plus_1(0) @action(name="action-2") @@ -64,13 +64,20 @@ def action_2(text1, text2): logger.log(f"action 2 triggered. text1 = {text1}, text2 = {text2}") -@action(name="wait-for-sec", blocking=True) -def action_2(sec): +@action(name="wait-for-sec", blocking=False) +def wait_for_sec(sec): sec = int(sec) logger.log(f"wait for {sec} sec.") time.sleep(sec) +@action(name="block-for-sec", blocking=True) +def block_for_sec(sec): + sec = int(sec) + logger.log(f"block for {sec} sec.") + time.sleep(sec) + + @action(name="eval") def eval_code(code: str): logger.log(f"running code {code}") From 5a942c4b8cd9465d4812eb997e96c5f94e51a37d Mon Sep 17 00:00:00 2001 From: lideming Date: Wed, 29 Nov 2023 10:48:24 +0800 Subject: [PATCH 024/114] perf: prevent useless renders --- .../components/dashboard/project/actions.tsx | 213 +++++++++--------- .../dashboard/project/platformProps.tsx | 127 ++++++----- neetbox/frontend/src/hooks/useMemoJSON.ts | 7 + 3 files changed, 186 insertions(+), 161 deletions(-) create mode 100644 neetbox/frontend/src/hooks/useMemoJSON.ts diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index fbe79132..e2a62f8c 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -8,9 +8,10 @@ import { Space, Typography, } from "@douyinfe/semi-ui"; -import { useContext, useState } from "react"; +import { memo, useContext, useState } from "react"; import { ProjectStatus, getProject } from "../../../services/projects"; import { ProjectContext } from "../../../pages/console/proejctDashboard"; +import { useMemoJSON } from "../../../hooks/useMemoJSON"; interface Props { actions: ProjectStatus["__action"]; @@ -18,7 +19,7 @@ interface Props { export function Actions({ actions }: Props) { const [blocking, setBlocking] = useState(false); - const actionList = Object.entries(actions?.value ?? {}); + const actionList = Object.entries(useMemoJSON(actions?.value ?? {})); return ( {actionList.length ? ( @@ -51,108 +52,110 @@ interface ActionItemProps { setBlocking: (blocking: boolean) => void; } -export function ActionItem({ - name, - actionOptions: options, - blocking, - setBlocking, -}: ActionItemProps) { - const [args, setArgs] = useState>(() => - Object.fromEntries( - Object.entries(options.args).map(([name, type]) => [ - name, - type == "str" ? '""' : type == "bool" ? "False" : "", - ]) - ) - ); - const [running, setCurrentBlocking] = useState(false); - const [result, setResult] = useState(null); - const { projectName } = useContext(ProjectContext)!; - const handleRun = () => { - if (options.blocking) setBlocking(true); - setCurrentBlocking(true); - getProject(projectName).sendAction( - name, - args, - ({ error: err, result: res }) => { - if (options.blocking) setBlocking(false); - setCurrentBlocking(false); - setResult(err ? `error:\n${err}` : `result:\n${JSON.stringify(res)}`); - } +export const ActionItem = memo( + ({ + name, + actionOptions: options, + blocking, + setBlocking, + }: ActionItemProps) => { + const [args, setArgs] = useState>(() => + Object.fromEntries( + Object.entries(options.args).map(([name, type]) => [ + name, + type == "str" ? '""' : type == "bool" ? "False" : "", + ]), + ), ); - }; - const renderContent = () => ( - - {name} - {options.description && ( -
- {options.description} -
- )} - {Object.entries(options.args).map(([argName, argType]) => ( - - - - {argName} - - - - {argType == "bool" ? ( - - setArgs({ - ...args, - [argName]: args[argName] == "True" ? "False" : "True", - }) - } - > - {args[argName]} - - ) : ( - setArgs({ ...args, [argName]: val })} - /> - )} - - - - ({argType}) - - - - ))} - - {result && ( -
{result}
- )} -
- ); - return ( - - - - ); -} + {name} + {options.description && ( +
+ {options.description} +
+ )} + {Object.entries(options.args).map(([argName, argType]) => ( + + + + {argName} + + + + {argType == "bool" ? ( + + setArgs({ + ...args, + [argName]: args[argName] == "True" ? "False" : "True", + }) + } + > + {args[argName]} + + ) : ( + setArgs({ ...args, [argName]: val })} + /> + )} + + + + ({argType}) + + + + ))} + + {result && ( +
{result}
+ )} +
+ ); + return ( + + + + ); + }, +); diff --git a/neetbox/frontend/src/components/dashboard/project/platformProps.tsx b/neetbox/frontend/src/components/dashboard/project/platformProps.tsx index 641de374..8e4f9da9 100644 --- a/neetbox/frontend/src/components/dashboard/project/platformProps.tsx +++ b/neetbox/frontend/src/components/dashboard/project/platformProps.tsx @@ -1,66 +1,81 @@ -import React from "react"; +import React, { memo } from "react"; import { Toast, Button, Card, CardGroup, Typography } from "@douyinfe/semi-ui"; import { IconCopy } from "@douyinfe/semi-icons"; +import { useMemoJSON } from "../../../hooks/useMemoJSON"; +import { ProjectStatus } from "../../../services/projects"; -function PropCard({ propName, propValue }): React.JSX.Element { - const { Text } = Typography; - const content = Array.isArray(propValue) ? propValue.join(" ") : propValue; - const nameMapping = { - username: "Launched by", - machine: "Machine type", - processor: "Processor name", - os_name: "System/OS name", - os_release: "Sys release ver", - architecture: "Python arch.", - python_build: "Python build", - python_version: "Python version", - }; - return ( - } - style={{ marginRight: 10 }} - size="small" - onClick={() => { - navigator.clipboard.writeText(propValue).then( - () => { - // copy success - Toast.info("Copied to clipboard"); - }, - () => { - // copy failed - Toast.error("Failed to copy"); - }, - ); - }} - > - } - > - {content} - - ); -} +const PropCard = memo( + ({ + propName, + propValue, + }: { + propName: string; + propValue: ProjectStatus["platform"]["value"][string]; + }) => { + const { Text } = Typography; + const content = Array.isArray(propValue) ? propValue.join(" ") : propValue; + const nameMapping = { + username: "Launched by", + machine: "Machine type", + processor: "Processor name", + os_name: "System/OS name", + os_release: "Sys release ver", + architecture: "Python arch.", + python_build: "Python build", + python_version: "Python version", + }; + return ( + } + style={{ marginRight: 10 }} + size="small" + onClick={() => { + navigator.clipboard.writeText(content).then( + () => { + // copy success + Toast.info("Copied to clipboard"); + }, + () => { + // copy failed + Toast.error("Failed to copy"); + }, + ); + }} + > + } + > + {content} + + ); + }, +); -export default function PlatformProps({ data }): React.JSX.Element { +export default function PlatformProps({ + data, +}: { + data: ProjectStatus["platform"]; +}): React.JSX.Element { + const memoData = useMemoJSON(data?.value); return (
- {(data?.value && - Object.entries(data.value).map(([key, value]) => ( + {(memoData && + Object.entries(memoData).map(([key, value]) => ( ))) || No Platform Info} diff --git a/neetbox/frontend/src/hooks/useMemoJSON.ts b/neetbox/frontend/src/hooks/useMemoJSON.ts new file mode 100644 index 00000000..650694ab --- /dev/null +++ b/neetbox/frontend/src/hooks/useMemoJSON.ts @@ -0,0 +1,7 @@ +import { useMemo } from "react"; + +/** Return the same ref if the data is not changed */ +export function useMemoJSON(data: T): T { + // eslint-disable-next-line react-hooks/exhaustive-deps + return useMemo(() => data, [JSON.stringify(data)]); +} From e2cda721c9ada1583da83d60654c0bb9968edb8a Mon Sep 17 00:00:00 2001 From: lideming Date: Wed, 29 Nov 2023 10:57:30 +0800 Subject: [PATCH 025/114] chore: add prettier --- .github/workflows/build-frontend.yml | 2 + neetbox/frontend/.eslintrc.cjs | 29 ++- neetbox/frontend/README.md | 34 +--- neetbox/frontend/package.json | 9 +- neetbox/frontend/src/components/Footer.tsx | 4 +- .../components/dashboard/project/actions.tsx | 190 +++++++----------- .../dashboard/project/hardware/cpugraph.tsx | 139 ++++++------- .../dashboard/project/hardware/gpugraph.tsx | 188 ++++++++--------- .../dashboard/project/hardware/index.tsx | 76 ++++--- .../dashboard/project/hardware/ramgraph.tsx | 140 ++++++------- .../dashboard/project/logs/logs.tsx | 32 +-- .../dashboard/project/platformProps.tsx | 14 +- neetbox/frontend/src/components/echarts.tsx | 6 +- neetbox/frontend/src/components/loading.tsx | 8 +- .../frontend/src/components/sectionTitle.tsx | 30 +-- .../frontend/src/components/themeSwitcher.tsx | 6 +- neetbox/frontend/src/main.tsx | 2 +- .../src/pages/console/proejctDashboard.tsx | 6 +- .../frontend/src/pages/console/sidebar.tsx | 8 +- .../frontend/src/pages/login/index.module.css | 4 +- neetbox/frontend/src/pages/login/index.tsx | 2 +- neetbox/frontend/src/services/projects.ts | 8 +- neetbox/frontend/src/styles/global.css | 6 +- neetbox/frontend/vite.config.ts | 33 +-- neetbox/frontend/yarn.lock | 5 + 25 files changed, 427 insertions(+), 554 deletions(-) diff --git a/.github/workflows/build-frontend.yml b/.github/workflows/build-frontend.yml index 4e0e9081..15806b2d 100644 --- a/.github/workflows/build-frontend.yml +++ b/.github/workflows/build-frontend.yml @@ -30,3 +30,5 @@ jobs: if: '!cancelled()' - run: yarn lint if: '!cancelled()' + - run: yarn prettier-check + if: '!cancelled()' diff --git a/neetbox/frontend/.eslintrc.cjs b/neetbox/frontend/.eslintrc.cjs index e36ceb19..29e4cff0 100644 --- a/neetbox/frontend/.eslintrc.cjs +++ b/neetbox/frontend/.eslintrc.cjs @@ -2,22 +2,19 @@ module.exports = { root: true, env: { browser: true, es2020: true }, extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - 'plugin:import/recommended', - 'plugin:import/typescript', + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + "plugin:import/recommended", + "plugin:import/typescript", ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], + ignorePatterns: ["dist", ".eslintrc.cjs"], + parser: "@typescript-eslint/parser", + plugins: ["react-refresh"], rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - 'import/order': 'warn', - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-unused-vars': 'warn', + "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], + "import/order": "warn", + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-unused-vars": "warn", }, -} +}; diff --git a/neetbox/frontend/README.md b/neetbox/frontend/README.md index 0d6babed..83db8b27 100644 --- a/neetbox/frontend/README.md +++ b/neetbox/frontend/README.md @@ -1,30 +1,16 @@ -# React + TypeScript + Vite +# Neet Center Frontend -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +## Dev -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration +```shell +yarn # install dev deps +yarn dev +``` -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: +It uses `http://127.0.0.1:5000` as backend server. See `vite.config.ts` to change. -- Configure the top-level `parserOptions` property like this: +## Build -```js -export default { - // other rules... - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['./tsconfig.json', './tsconfig.node.json'], - tsconfigRootDir: __dirname, - }, -} ``` - -- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` -- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list +yarn build +``` diff --git a/neetbox/frontend/package.json b/neetbox/frontend/package.json index 1ae3d769..7888ae22 100644 --- a/neetbox/frontend/package.json +++ b/neetbox/frontend/package.json @@ -8,7 +8,9 @@ "build": "vite build", "tsc": "tsc", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 20", - "preview": "vite preview" + "preview": "vite preview", + "prettier-check": "prettier -c .", + "prettier": "prettier -w ." }, "dependencies": { "@douyinfe/semi-ui": "^2.47.0", @@ -33,7 +35,12 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.4", + "prettier": "^3.1.0", "typescript": "^5.2.2", "vite": "^5.0.0" + }, + "prettier": { + "trailingComma": "all", + "printWidth": 110 } } diff --git a/neetbox/frontend/src/components/Footer.tsx b/neetbox/frontend/src/components/Footer.tsx index 89c926ab..3aa624b6 100644 --- a/neetbox/frontend/src/components/Footer.tsx +++ b/neetbox/frontend/src/components/Footer.tsx @@ -6,9 +6,7 @@ export default function FooterContent(): React.JSX.Element {

-
- © 2023 - 2023 Neet Design. All rights reserved. -
+
© 2023 - 2023 Neet Design. All rights reserved.
); } diff --git a/neetbox/frontend/src/components/dashboard/project/actions.tsx b/neetbox/frontend/src/components/dashboard/project/actions.tsx index e2a62f8c..ba31f406 100644 --- a/neetbox/frontend/src/components/dashboard/project/actions.tsx +++ b/neetbox/frontend/src/components/dashboard/project/actions.tsx @@ -1,13 +1,4 @@ -import { - Button, - Checkbox, - Col, - Input, - Popover, - Row, - Space, - Typography, -} from "@douyinfe/semi-ui"; +import { Button, Checkbox, Col, Input, Popover, Row, Space, Typography } from "@douyinfe/semi-ui"; import { memo, useContext, useState } from "react"; import { ProjectStatus, getProject } from "../../../services/projects"; import { ProjectContext } from "../../../pages/console/proejctDashboard"; @@ -52,110 +43,79 @@ interface ActionItemProps { setBlocking: (blocking: boolean) => void; } -export const ActionItem = memo( - ({ - name, - actionOptions: options, - blocking, - setBlocking, - }: ActionItemProps) => { - const [args, setArgs] = useState>(() => - Object.fromEntries( - Object.entries(options.args).map(([name, type]) => [ - name, - type == "str" ? '""' : type == "bool" ? "False" : "", - ]), - ), - ); - const [running, setCurrentBlocking] = useState(false); - const [result, setResult] = useState(null); - const { projectName } = useContext(ProjectContext)!; - const handleRun = () => { - if (options.blocking) setBlocking(true); - setCurrentBlocking(true); - getProject(projectName).sendAction( +export const ActionItem = memo(({ name, actionOptions: options, blocking, setBlocking }: ActionItemProps) => { + const [args, setArgs] = useState>(() => + Object.fromEntries( + Object.entries(options.args).map(([name, type]) => [ name, - args, - ({ error: err, result: res }) => { - if (options.blocking) setBlocking(false); - setCurrentBlocking(false); - setResult(err ? `error:\n${err}` : `result:\n${JSON.stringify(res)}`); - }, - ); - }; - const renderContent = () => ( - - {name} - {options.description && ( -
- {options.description} -
- )} - {Object.entries(options.args).map(([argName, argType]) => ( - - - - {argName} - - - - {argType == "bool" ? ( - - setArgs({ - ...args, - [argName]: args[argName] == "True" ? "False" : "True", - }) - } - > - {args[argName]} - - ) : ( - setArgs({ ...args, [argName]: val })} - /> - )} - - - - ({argType}) - - - - ))} - - {result && ( -
{result}
- )} -
- ); - return ( - - - - ); - }, -); + + {argName} + + + {argType == "bool" ? ( + + setArgs({ + ...args, + [argName]: args[argName] == "True" ? "False" : "True", + }) + } + > + {args[argName]} + + ) : ( + setArgs({ ...args, [argName]: val })} + /> + )} + + + ({argType}) + + + ))} + + {result &&
{result}
} + + ); + return ( + + + + ); +}); diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx index c7e9831f..7235bf37 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/cpugraph.tsx @@ -1,75 +1,64 @@ -import { useMemo } from "react"; -import { ECharts } from "../../../echarts"; -import { ProjectStatus } from "../../../../services/projects"; - -export const CPUGraph = ({ - hardwareData, -}: { - hardwareData: Array; -}) => { - const cpus = hardwareData[0].value.cpus; - const initialOption = () => { - return { - backgroundColor: "transparent", - animation: false, - tooltip: { - trigger: "axis", - }, - grid: { - top: 30, - bottom: 30, - }, - title: { - text: `CPU (${cpus.length} threads)`, - textStyle: { - fontSize: 12, - }, - }, - // legend: { - // data: cpus.map((cpu) => `CPU${cpu.id}`), - // }, - xAxis: { - type: "time", - }, - yAxis: { - type: "value", - max: cpus.length * 100, - axisLabel: { - formatter: (x) => x + " %", - }, - }, - series: [], - } as echarts.EChartsOption; - }; - - const updatingOption = useMemo(() => { - const latestTime = hardwareData[hardwareData.length - 1].timestamp; - const newOption = { - series: cpus.map((cpu) => ({ - name: `CPU${cpu.id}`, - type: "line", - stack: "cpu", - areaStyle: {}, - symbol: null, - data: hardwareData.map((x) => [ - x.timestamp * 1000, - x.value.cpus[cpu.id].percent, - ]), - })), - xAxis: { - min: (latestTime - 60) * 1000, - max: latestTime * 1000, - data: new Array(10).fill(0).map((x, i) => i), - }, - } as echarts.EChartsOption; - return newOption; - }, [hardwareData]); - - return ( - - ); -}; +import { useMemo } from "react"; +import { ECharts } from "../../../echarts"; +import { ProjectStatus } from "../../../../services/projects"; + +export const CPUGraph = ({ hardwareData }: { hardwareData: Array }) => { + const cpus = hardwareData[0].value.cpus; + const initialOption = () => { + return { + backgroundColor: "transparent", + animation: false, + tooltip: { + trigger: "axis", + }, + grid: { + top: 30, + bottom: 30, + }, + title: { + text: `CPU (${cpus.length} threads)`, + textStyle: { + fontSize: 12, + }, + }, + // legend: { + // data: cpus.map((cpu) => `CPU${cpu.id}`), + // }, + xAxis: { + type: "time", + }, + yAxis: { + type: "value", + max: cpus.length * 100, + axisLabel: { + formatter: (x) => x + " %", + }, + }, + series: [], + } as echarts.EChartsOption; + }; + + const updatingOption = useMemo(() => { + const latestTime = hardwareData[hardwareData.length - 1].timestamp; + const newOption = { + series: cpus.map((cpu) => ({ + name: `CPU${cpu.id}`, + type: "line", + stack: "cpu", + areaStyle: {}, + symbol: null, + data: hardwareData.map((x) => [x.timestamp * 1000, x.value.cpus[cpu.id].percent]), + })), + xAxis: { + min: (latestTime - 60) * 1000, + max: latestTime * 1000, + data: new Array(10).fill(0).map((x, i) => i), + }, + } as echarts.EChartsOption; + return newOption; + }, [hardwareData]); + + return ( + + ); +}; diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx index 22796a9d..0036de1f 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/gpugraph.tsx @@ -1,99 +1,89 @@ -import { useMemo } from "react"; -import { ECharts } from "../../../echarts"; -import { ProjectStatus } from "../../../../services/projects"; - -export const GPUGraph = ({ - hardwareData, - gpuId, -}: { - hardwareData: Array; - gpuId: number; -}) => { - const gpus = hardwareData[0].value.gpus; - const initialOption = () => { - return { - backgroundColor: "transparent", - animation: false, - tooltip: { - trigger: "axis", - }, - grid: { - top: 30, - bottom: 30, - }, - title: { - text: `GPU${gpuId}: ${gpus[gpuId].name}`, - textStyle: { - fontSize: 12, - }, - }, - legend: { - data: [`Load`, `Memory`], - }, - xAxis: { - type: "time", - }, - yAxis: [ - { - type: "value", - max: 100, - axisLabel: { - formatter: (x) => x + " %", - }, - }, - { - type: "value", - position: "right", - splitLine: null, - axisLabel: { - formatter: (x) => x.toFixed(1) + " GB", - }, - max: gpus[gpuId].memoryTotal / 1024, - }, - ], - series: [], - } as echarts.EChartsOption; - }; - - const updatingOption = useMemo(() => { - const latestTime = hardwareData[hardwareData.length - 1].timestamp; - const newOption = { - series: [ - { - name: `Load`, - type: "line", - areaStyle: null, - symbol: null, - data: hardwareData.map((x) => [ - x.timestamp * 1000, - x.value.gpus[gpuId].load * 100, - ]), - }, - { - name: `Memory`, - type: "line", - areaStyle: {}, - symbol: null, - yAxisIndex: 1, - data: hardwareData.map((x) => [ - x.timestamp * 1000, - x.value.gpus[gpuId].memoryUsed / 1024, - ]), - }, - ], - xAxis: { - min: (latestTime - 60) * 1000, - max: latestTime * 1000, - }, - } as echarts.EChartsOption; - return newOption; - }, [hardwareData]); - - return ( - - ); -}; +import { useMemo } from "react"; +import { ECharts } from "../../../echarts"; +import { ProjectStatus } from "../../../../services/projects"; + +export const GPUGraph = ({ + hardwareData, + gpuId, +}: { + hardwareData: Array; + gpuId: number; +}) => { + const gpus = hardwareData[0].value.gpus; + const initialOption = () => { + return { + backgroundColor: "transparent", + animation: false, + tooltip: { + trigger: "axis", + }, + grid: { + top: 30, + bottom: 30, + }, + title: { + text: `GPU${gpuId}: ${gpus[gpuId].name}`, + textStyle: { + fontSize: 12, + }, + }, + legend: { + data: [`Load`, `Memory`], + }, + xAxis: { + type: "time", + }, + yAxis: [ + { + type: "value", + max: 100, + axisLabel: { + formatter: (x) => x + " %", + }, + }, + { + type: "value", + position: "right", + splitLine: null, + axisLabel: { + formatter: (x) => x.toFixed(1) + " GB", + }, + max: gpus[gpuId].memoryTotal / 1024, + }, + ], + series: [], + } as echarts.EChartsOption; + }; + + const updatingOption = useMemo(() => { + const latestTime = hardwareData[hardwareData.length - 1].timestamp; + const newOption = { + series: [ + { + name: `Load`, + type: "line", + areaStyle: null, + symbol: null, + data: hardwareData.map((x) => [x.timestamp * 1000, x.value.gpus[gpuId].load * 100]), + }, + { + name: `Memory`, + type: "line", + areaStyle: {}, + symbol: null, + yAxisIndex: 1, + data: hardwareData.map((x) => [x.timestamp * 1000, x.value.gpus[gpuId].memoryUsed / 1024]), + }, + ], + xAxis: { + min: (latestTime - 60) * 1000, + max: latestTime * 1000, + }, + } as echarts.EChartsOption; + return newOption; + }, [hardwareData]); + + return ( + + ); +}; diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx index 120ed220..ce851e9e 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/index.tsx @@ -1,41 +1,35 @@ -import { Typography } from "@douyinfe/semi-ui"; -import { ProjectStatus } from "../../../../services/projects"; -import { CPUGraph } from "./cpugraph"; -import { GPUGraph } from "./gpugraph"; -import { RAMGraph } from "./ramgraph"; - -export function Hardware({ - hardwareData, -}: { - hardwareData: Array; -}) { - return ( -
- {hardwareData.every((x) => x.value.gpus.length) ? ( - hardwareData[0].value.gpus.map((_, i) => ( - - )) - ) : ( - - )} - {hardwareData.every((x) => x.value.cpus.length) ? ( - - ) : ( - - )} - {hardwareData.every((x) => x.value.ram) ? ( - - ) : ( - - )} -
- ); -} - -function NoInfoLabel({ text }: { text: string }) { - return ( - - {text} - - ); -} +import { Typography } from "@douyinfe/semi-ui"; +import { ProjectStatus } from "../../../../services/projects"; +import { CPUGraph } from "./cpugraph"; +import { GPUGraph } from "./gpugraph"; +import { RAMGraph } from "./ramgraph"; + +export function Hardware({ hardwareData }: { hardwareData: Array }) { + return ( +
+ {hardwareData.every((x) => x.value.gpus.length) ? ( + hardwareData[0].value.gpus.map((_, i) => ) + ) : ( + + )} + {hardwareData.every((x) => x.value.cpus.length) ? ( + + ) : ( + + )} + {hardwareData.every((x) => x.value.ram) ? ( + + ) : ( + + )} +
+ ); +} + +function NoInfoLabel({ text }: { text: string }) { + return ( + + {text} + + ); +} diff --git a/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx b/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx index c4d1ad85..d2802f29 100644 --- a/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx +++ b/neetbox/frontend/src/components/dashboard/project/hardware/ramgraph.tsx @@ -1,74 +1,66 @@ -import { useMemo } from "react"; -import { ECharts } from "../../../echarts"; -import { ProjectStatus } from "../../../../services/projects"; - -export const RAMGraph = ({ - hardwareData, -}: { - hardwareData: Array; -}) => { - const initialOption = () => { - return { - backgroundColor: "transparent", - animation: false, - tooltip: { - trigger: "axis", - }, - title: { - text: `RAM`, - textStyle: { - fontSize: 12, - }, - }, - grid: { - top: 30, - bottom: 30, - }, - legend: { - data: [`RAM Used`], - }, - xAxis: { - type: "time", - }, - yAxis: [ - { - type: "value", - position: "right", - axisLabel: { - formatter: (x) => x.toFixed(1) + " GB", - }, - max: hardwareData[0].value.ram.total, - }, - ], - series: [], - } as echarts.EChartsOption; - }; - - const updatingOption = useMemo(() => { - const latestTime = hardwareData[hardwareData.length - 1].timestamp; - const newOption = { - series: [ - { - name: `RAM Used`, - type: "line", - areaStyle: {}, - symbol: null, - data: hardwareData.map((x) => [x.timestamp * 1000, x.value.ram.used]), - }, - ], - xAxis: { - min: (latestTime - 60) * 1000, - max: latestTime * 1000, - }, - } as echarts.EChartsOption; - return newOption; - }, [hardwareData]); - - return ( - - ); -}; +import { useMemo } from "react"; +import { ECharts } from "../../../echarts"; +import { ProjectStatus } from "../../../../services/projects"; + +export const RAMGraph = ({ hardwareData }: { hardwareData: Array }) => { + const initialOption = () => { + return { + backgroundColor: "transparent", + animation: false, + tooltip: { + trigger: "axis", + }, + title: { + text: `RAM`, + textStyle: { + fontSize: 12, + }, + }, + grid: { + top: 30, + bottom: 30, + }, + legend: { + data: [`RAM Used`], + }, + xAxis: { + type: "time", + }, + yAxis: [ + { + type: "value", + position: "right", + axisLabel: { + formatter: (x) => x.toFixed(1) + " GB", + }, + max: hardwareData[0].value.ram.total, + }, + ], + series: [], + } as echarts.EChartsOption; + }; + + const updatingOption = useMemo(() => { + const latestTime = hardwareData[hardwareData.length - 1].timestamp; + const newOption = { + series: [ + { + name: `RAM Used`, + type: "line", + areaStyle: {}, + symbol: null, + data: hardwareData.map((x) => [x.timestamp * 1000, x.value.ram.used]), + }, + ], + xAxis: { + min: (latestTime - 60) * 1000, + max: latestTime * 1000, + }, + } as echarts.EChartsOption; + return newOption; + }, [hardwareData]); + + return ( + + ); +}; diff --git a/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx index f3abdbbb..e9e9378a 100644 --- a/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx +++ b/neetbox/frontend/src/components/dashboard/project/logs/logs.tsx @@ -7,19 +7,14 @@ interface Props { projectName: string; } -function AutoScrolling({ - style, - children, -}: React.PropsWithChildren<{ style: React.CSSProperties }>) { +function AutoScrolling({ style, children }: React.PropsWithChildren<{ style: React.CSSProperties }>) { const containerRef = useRef(null!); const [following, setFollowing] = useState(true); const [renderingElement, setRenderingElement] = useState(children); useEffect(() => { const dom = containerRef.current; if (dom) { - setFollowing( - Math.abs(dom.scrollHeight - dom.clientHeight - dom.scrollTop) < 30, - ); + setFollowing(Math.abs(dom.scrollHeight - dom.clientHeight - dom.scrollTop) < 30); } setRenderingElement(children); }, [children]); @@ -38,12 +33,7 @@ function AutoScrolling({ export const Logs = React.memo(({ projectName }: Props) => { const logs = useProjectLogs(projectName); - return ( - } - /> - ); + return } />; }); const LogItems = ({ logs }: { logs: LogData[] }) => { @@ -52,12 +42,7 @@ const LogItems = ({ logs }: { logs: LogData[] }) => { function getColorFromWhom(whom: string) { const hue = - 50 + - ((whom - .split("") - .reduce((prev, char) => ((prev * 11) % 360) + char.charCodeAt(0), 0) * - 233) % - 200); + 50 + ((whom.split("").reduce((prev, char) => ((prev * 11) % 360) + char.charCodeAt(0), 0) * 233) % 200); return `hsl(${hue}, 70%, var(--log-tag-bg-l))`; } @@ -67,13 +52,8 @@ const LogItem = React.memo(({ data }: { data: LogData }) => { return (
{data.datetime}{" "} - - {prefix} - {" "} - + {prefix}{" "} + {data.whom} {" "} {data.msg} diff --git a/neetbox/frontend/src/components/dashboard/project/platformProps.tsx b/neetbox/frontend/src/components/dashboard/project/platformProps.tsx index 8e4f9da9..8f86c112 100644 --- a/neetbox/frontend/src/components/dashboard/project/platformProps.tsx +++ b/neetbox/frontend/src/components/dashboard/project/platformProps.tsx @@ -5,13 +5,7 @@ import { useMemoJSON } from "../../../hooks/useMemoJSON"; import { ProjectStatus } from "../../../services/projects"; const PropCard = memo( - ({ - propName, - propValue, - }: { - propName: string; - propValue: ProjectStatus["platform"]["value"][string]; - }) => { + ({ propName, propValue }: { propName: string; propValue: ProjectStatus["platform"]["value"][string] }) => { const { Text } = Typography; const content = Array.isArray(propValue) ? propValue.join(" ") : propValue; const nameMapping = { @@ -65,11 +59,7 @@ const PropCard = memo( }, ); -export default function PlatformProps({ - data, -}: { - data: ProjectStatus["platform"]; -}): React.JSX.Element { +export default function PlatformProps({ data }: { data: ProjectStatus["platform"] }): React.JSX.Element { const memoData = useMemoJSON(data?.value); return (
diff --git a/neetbox/frontend/src/components/echarts.tsx b/neetbox/frontend/src/components/echarts.tsx index 3774e45d..a708be2e 100644 --- a/neetbox/frontend/src/components/echarts.tsx +++ b/neetbox/frontend/src/components/echarts.tsx @@ -12,9 +12,7 @@ export interface EChartsProps { export const ECharts = (props: EChartsProps) => { const chartContainerRef = useRef(null); const chartRef = useRef(null!); - const [echartsModule, setEchartsModule] = useState( - null - ); + const [echartsModule, setEchartsModule] = useState(null); const { darkMode } = useTheme(); useEffect(() => { @@ -25,7 +23,7 @@ export const ECharts = (props: EChartsProps) => { if (echartsModule) { const chart = echartsModule.init( chartContainerRef.current, - darkMode ? "dark" : null + darkMode ? "dark" : null, // { renderer: "svg" }, ); diff --git a/neetbox/frontend/src/components/loading.tsx b/neetbox/frontend/src/components/loading.tsx index 897feb73..9bc307ae 100644 --- a/neetbox/frontend/src/components/loading.tsx +++ b/neetbox/frontend/src/components/loading.tsx @@ -1,12 +1,6 @@ import { Spin } from "@douyinfe/semi-ui"; -export default function Loading({ - width = "", - height = "100px", -}: { - width?: string; - height?: string; -}) { +export default function Loading({ width = "", height = "100px" }: { width?: string; height?: string }) { return (
- - {props.title} - -
- ); -} +import { Typography } from "@douyinfe/semi-ui"; + +interface Props { + title: string; +} + +export function SectionTitle(props: Props) { + return ( +
+ + {props.title} + +
+ ); +} diff --git a/neetbox/frontend/src/components/themeSwitcher.tsx b/neetbox/frontend/src/components/themeSwitcher.tsx index 1c93bf70..6133acbe 100644 --- a/neetbox/frontend/src/components/themeSwitcher.tsx +++ b/neetbox/frontend/src/components/themeSwitcher.tsx @@ -31,9 +31,5 @@ export function ThemeContextProvider(props: React.PropsWithChildren) { } }, [darkMode]); - return ( - - {props.children} - - ); + return {props.children}; } diff --git a/neetbox/frontend/src/main.tsx b/neetbox/frontend/src/main.tsx index a32b13e6..8253e6de 100644 --- a/neetbox/frontend/src/main.tsx +++ b/neetbox/frontend/src/main.tsx @@ -34,5 +34,5 @@ ReactDOM.createRoot(document.getElementById("root")!).render( - + , ); diff --git a/neetbox/frontend/src/pages/console/proejctDashboard.tsx b/neetbox/frontend/src/pages/console/proejctDashboard.tsx index e52e84d5..0832a745 100644 --- a/neetbox/frontend/src/pages/console/proejctDashboard.tsx +++ b/neetbox/frontend/src/pages/console/proejctDashboard.tsx @@ -9,9 +9,7 @@ import Loading from "../../components/loading"; import { Hardware } from "../../components/dashboard/project/hardware"; import { SectionTitle } from "../../components/sectionTitle"; -export const ProjectContext = createContext<{ projectName: string } | null>( - null -); +export const ProjectContext = createContext<{ projectName: string } | null>(null); export default function ProjectDashboardButRecreateOnRouteChange() { const { projectName } = useParams(); @@ -29,7 +27,7 @@ function ProjectDashboard() { () => ({ projectName, }), - [projectName] + [projectName], ); return ( diff --git a/neetbox/frontend/src/pages/console/sidebar.tsx b/neetbox/frontend/src/pages/console/sidebar.tsx index 4c960b7a..e5c89e54 100644 --- a/neetbox/frontend/src/pages/console/sidebar.tsx +++ b/neetbox/frontend/src/pages/console/sidebar.tsx @@ -10,13 +10,9 @@ export default function ConsoleNavBar() { return (