From 5021ab8d2faf4d62fc4d83dd490f1ac4709ce738 Mon Sep 17 00:00:00 2001 From: forumi0721 Date: Sun, 23 Feb 2025 13:52:44 +0900 Subject: [PATCH 01/11] Update korean translations --- web/src/i18n/locales/ko.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/web/src/i18n/locales/ko.ts b/web/src/i18n/locales/ko.ts index d4f8805..fd5affc 100644 --- a/web/src/i18n/locales/ko.ts +++ b/web/src/i18n/locales/ko.ts @@ -14,8 +14,7 @@ const ko = { placeholderPassword2: '비밀번호를 다시 입력하세요.', noEmptyUsername: '사용자 이름은 비어있을 수 없습니다.', noEmptyPassword: '비밀번호는 비어있을 수 없습니다.', - noAccount: - '사용자 정보를 불러오는 데 실패했습니다. 페이지를 새로고침하거나 비밀번호를 초기화하세요.', + noAccount: '사용자 정보를 불러오는 데 실패했습니다. 페이지를 새로고침하거나 비밀번호를 초기화하세요.', invalidUser: '사용자 이름이나 비밀번호가 틀렸습니다.', error: '알 수 없는 오류', changePassword: '비밀번호 변경', @@ -28,7 +27,8 @@ const ko = { cancel: '취소', loginButtonText: '로그인', tips: { - reset1: '비밀번호를 재설정하려면 NanoKVM의 BOOT 버튼을 10초 동안 누르고 계세요.', + reset1: + '비밀번호를 재설정하려면 NanoKVM의 BOOT 버튼을 10초 동안 누르고 계세요.', reset2: '자세한 절차는 이 문서를 참조하세요:', reset3: '웹 기본 계정:', reset4: 'SSH 기본 계정:', @@ -89,6 +89,7 @@ const ko = { title: '이미지', loading: '불러오는 중...', empty: '아무것도 없습니다.', + cdrom: 'CD-ROM 모드로 이미지 마운트', mountFailed: '이미지 마운트 실패', mountDesc: '일부 시스템에서는 이미지를 마운트하기 전에 원격 호스트에서 가상 디스크를 제거해야 합니다.', @@ -99,7 +100,7 @@ const ko = { usb3: '컴퓨터에서 가상 디스크를 열고 이미지 파일을 가상 디스크의 루트 디렉토리로 복사하세요.', scp1: 'NanoKVM과 컴퓨터가 동일한 로컬 네트워크에 있는지 확인하세요.', scp2: '컴퓨터에서 터미널을 열고 SCP 명령을 사용하여 이미지 파일을 NanoKVM의 /data 디렉터리에 업로드하세요.', - scp3: '예: scp [이미지 파일 경로] root@[NanoKVM IP 주소]:/data', + scp3: '예시: scp [이미지 파일 경로] root@[NanoKVM IP 주소]:/data', tfCard: 'TF 카드', tf1: '이 방법은 Linux 시스템에서 지원됩니다', tf2: 'NanoKVM에서 TF 카드를 가져옵니다(전체 버전의 경우 먼저 케이스를 분해하세요).', @@ -116,7 +117,7 @@ const ko = { runFailed: '실행 실패', attention: '주의', delDesc: '이 파일을 정말로 삭제합니까?', - confirm: '예', + confirm: '네', cancel: '아니오', delete: '삭제', close: '닫기' @@ -222,7 +223,8 @@ const ko = { upTailscale: 'tailscale을 NanoKVM 의 다음 경로에 업로드 했습니다. : /usr/bin/', upTailscaled: 'tailscaled을 NanoKVM 의 다음 경로에 업로드 했습니다. : /usr/sbin/', refresh: '현재 페이지 새로고침', - notLogin: '이 기기는 현재 연동 되지 않았습니다. 로그인해서 계정에 이 장치를 연동하세요.', + notLogin: + '이 기기는 현재 연동 되지 않았습니다. 로그인해서 계정에 이 장치를 연동하세요.', urlPeriod: '이 주소는 10분간 유효합니다.', login: '로그인', loginSuccess: '로그인 성공', @@ -233,7 +235,7 @@ const ko = { logout: '로그아웃', logout2: '정말로 로그아웃 합니까?', uninstall: 'Tailscale 제거', - okBtn: '예', + okBtn: '네', cancelBtn: '아니오' }, update: { @@ -253,6 +255,10 @@ const ko = { updateBtn: '업데이트', logoutBtn: '로그아웃' } + }, + error: { + title: '문제가 발생했습니다.', + refresh: '새로고침' } } }; From a920fcc58a40b69f5040d9fa1b7b36a9fb636e17 Mon Sep 17 00:00:00 2001 From: forumi0721 Date: Sun, 23 Feb 2025 15:43:13 +0900 Subject: [PATCH 02/11] Add image list refresh button --- web/src/i18n/locales/en.ts | 1 + web/src/i18n/locales/ko.ts | 1 + web/src/pages/desktop/menu/image/images.tsx | 9 +++++- web/src/pages/desktop/menu/image/index.tsx | 36 +++++++++++++++------ 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/web/src/i18n/locales/en.ts b/web/src/i18n/locales/en.ts index d776aa6..ac0acdb 100644 --- a/web/src/i18n/locales/en.ts +++ b/web/src/i18n/locales/en.ts @@ -93,6 +93,7 @@ const en = { mountFailed: 'Mount Failed', mountDesc: "In some systems, it's necessary to eject the virtual disk on the remote host before mounting the image.", + refresh: 'Refresh the image list', tips: { title: 'How to upload', usb1: 'Connect the NanoKVM to your computer via USB.', diff --git a/web/src/i18n/locales/ko.ts b/web/src/i18n/locales/ko.ts index fd5affc..da558b6 100644 --- a/web/src/i18n/locales/ko.ts +++ b/web/src/i18n/locales/ko.ts @@ -93,6 +93,7 @@ const ko = { mountFailed: '이미지 마운트 실패', mountDesc: '일부 시스템에서는 이미지를 마운트하기 전에 원격 호스트에서 가상 디스크를 제거해야 합니다.', + refresh: '이미지 목록 새로고침', tips: { title: '업로드 방법', usb1: 'USB를 통해 NanoKVM을 컴퓨터에 연결하세요.', diff --git a/web/src/pages/desktop/menu/image/images.tsx b/web/src/pages/desktop/menu/image/images.tsx index c68ff45..92c32a1 100644 --- a/web/src/pages/desktop/menu/image/images.tsx +++ b/web/src/pages/desktop/menu/image/images.tsx @@ -16,9 +16,10 @@ import { client } from '@/lib/websocket.ts'; type ImagesProps = { cdrom: boolean; setIsMounted: (isMounted: boolean) => void; + onRefresh?: () => void; }; -export const Images = ({ cdrom, setIsMounted }: ImagesProps) => { +export const Images = ({ cdrom, setIsMounted, onRefresh }: ImagesProps) => { const { t } = useTranslation(); const [notify, contextHolder] = notification.useNotification(); @@ -31,6 +32,12 @@ export const Images = ({ cdrom, setIsMounted }: ImagesProps) => { getImages(); }, []); + useEffect(() => { + if (onRefresh) { + onRefresh(getImages); + } + }, [onRefresh]); + function getImages() { if (isLoading) return; setIsLoading(true); diff --git a/web/src/pages/desktop/menu/image/index.tsx b/web/src/pages/desktop/menu/image/index.tsx index d93da94..d4b9688 100644 --- a/web/src/pages/desktop/menu/image/index.tsx +++ b/web/src/pages/desktop/menu/image/index.tsx @@ -1,7 +1,7 @@ -import { useEffect, useState } from 'react'; -import { Divider, Popover, Switch, Tooltip } from 'antd'; +import { useEffect, useRef, useState } from 'react'; +import { Button, Divider, Popover, Switch, Tooltip } from 'antd'; import clsx from 'clsx'; -import { DiscIcon } from 'lucide-react'; +import { DiscIcon, RefreshCwIcon } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { useMediaQuery } from 'react-responsive'; @@ -18,6 +18,8 @@ export const Image = () => { const [isMounted, setIsMounted] = useState(false); const [cdrom, setCdrom] = useState(false); + const getImagesRef = useRef<() => void>(() => {}); + useEffect(() => { getMountedImage().then((rsp) => { if (rsp.code !== 0) return; @@ -30,6 +32,12 @@ export const Image = () => { }); }, []); + const refreshImages = () => { + if (getImagesRef.current) { + getImagesRef.current(); + } + }; + const content = (
@@ -38,18 +46,26 @@ export const Image = () => {
- -
- CD-ROM +
+ +
+ CD-ROM - setCdrom(checked)}> -
-
+ setCdrom(checked)}> +
+ + + +
- {isPopoverOpen && } + {isPopoverOpen && ( + (getImagesRef.current = func)} /> + )} ); From 148fb4e37bd5d966fa6da4636a55d48b090df043 Mon Sep 17 00:00:00 2001 From: forumi0721 Date: Sun, 23 Feb 2025 15:51:07 +0900 Subject: [PATCH 03/11] Fix build error --- web/src/pages/desktop/menu/image/images.tsx | 2 +- web/src/pages/desktop/menu/image/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/pages/desktop/menu/image/images.tsx b/web/src/pages/desktop/menu/image/images.tsx index 92c32a1..29b3db8 100644 --- a/web/src/pages/desktop/menu/image/images.tsx +++ b/web/src/pages/desktop/menu/image/images.tsx @@ -16,7 +16,7 @@ import { client } from '@/lib/websocket.ts'; type ImagesProps = { cdrom: boolean; setIsMounted: (isMounted: boolean) => void; - onRefresh?: () => void; + onRefresh?: (callback: () => void) => void; }; export const Images = ({ cdrom, setIsMounted, onRefresh }: ImagesProps) => { diff --git a/web/src/pages/desktop/menu/image/index.tsx b/web/src/pages/desktop/menu/image/index.tsx index d4b9688..ec3a14e 100644 --- a/web/src/pages/desktop/menu/image/index.tsx +++ b/web/src/pages/desktop/menu/image/index.tsx @@ -64,7 +64,7 @@ export const Image = () => { {isPopoverOpen && ( - (getImagesRef.current = func)} /> + (getImagesRef.current = callback)} /> )} ); From e3575e629c0a19d61eff3c730a1c7c5eb51ef33e Mon Sep 17 00:00:00 2001 From: forumi0721 Date: Thu, 27 Feb 2025 00:11:33 +0900 Subject: [PATCH 04/11] Added Draggable Functionality for Main Menu Positioning --- web/package.json | 3 +- web/pnpm-lock.yaml | 22 ++++++ web/src/pages/desktop/menu/index.tsx | 103 ++++++++++++++------------- 3 files changed, 77 insertions(+), 51 deletions(-) diff --git a/web/package.json b/web/package.json index 41ff665..527e583 100644 --- a/web/package.json +++ b/web/package.json @@ -25,6 +25,7 @@ "lucide-react": "^0.469.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-draggable": "^4.4.0", "react-error-boundary": "^4.1.2", "react-helmet-async": "^2.0.5", "react-i18next": "^14.1.3", @@ -66,4 +67,4 @@ "public" ] } -} \ No newline at end of file +} diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 398ebfc..d1dc409 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + react-draggable: + specifier: ^4.4.0 + version: 4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-error-boundary: specifier: ^4.1.2 version: 4.1.2(react@18.3.1) @@ -1166,6 +1169,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -2356,6 +2363,12 @@ packages: peerDependencies: react: ^18.3.1 + react-draggable@4.4.6: + resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==} + peerDependencies: + react: '>= 16.3.0' + react-dom: '>= 16.3.0' + react-error-boundary@4.1.2: resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} peerDependencies: @@ -3961,6 +3974,8 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clsx@1.2.1: {} + clsx@2.1.1: {} color-convert@2.0.1: @@ -5242,6 +5257,13 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-draggable@4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + clsx: 1.2.1 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-error-boundary@4.1.2(react@18.3.1): dependencies: '@babel/runtime': 7.26.0 diff --git a/web/src/pages/desktop/menu/index.tsx b/web/src/pages/desktop/menu/index.tsx index fd8830f..a36126c 100644 --- a/web/src/pages/desktop/menu/index.tsx +++ b/web/src/pages/desktop/menu/index.tsx @@ -3,6 +3,7 @@ import { Divider } from 'antd'; import clsx from 'clsx'; import { useAtom } from 'jotai'; import { MenuIcon, XIcon } from 'lucide-react'; +import Draggable from 'react-draggable'; import { getMenuDisabledItems } from '@/lib/localstorage.ts'; import { menuDisabledItemsAtom } from '@/jotai/settings.ts'; @@ -30,60 +31,62 @@ export const Menu = () => { }, []); return ( -
-
-
-
- sipeed -
- - - - - - - {!menuDisabledItems.includes('image') && } - {!menuDisabledItems.includes('download') && } - {!menuDisabledItems.includes('script') &&