fix: mounted image were not being detected correctly

perf: add support for CD-ROM mode when mounting image
perf: add a loading state during login
perf: add changelog link in settings
This commit is contained in:
wj-xiao
2025-02-21 14:52:48 +08:00
parent 9c0c50140b
commit b5e48a07e8
10 changed files with 116 additions and 71 deletions

View File

@@ -11,9 +11,15 @@ export function getMountedImage() {
}
// mount/unmount image
export function mountImage(file?: string) {
export function mountImage(file?: string, cdrom?: boolean) {
const data = {
file: file ? file : ''
file: file ? file : '',
cdrom: cdrom
};
return http.post('/api/storage/image/mount', data);
}
// get CD-ROM flag
export function getCdRom() {
return http.get('/api/storage/cdrom');
}

View File

@@ -14,6 +14,8 @@ import { Tips } from './tips.tsx';
export const Login = () => {
const navigate = useNavigate();
const { t } = useTranslation();
const [isLoading, setIsloading] = useState(false);
const [msg, setMsg] = useState('');
useEffect(() => {
@@ -29,6 +31,9 @@ export const Login = () => {
}, [msg]);
function login(values: any) {
if (isLoading) return;
setIsloading(true);
const username = values.username;
const password = encrypt(values.password);
@@ -48,6 +53,9 @@ export const Login = () => {
})
.catch(() => {
setMsg(t('auth.error'));
})
.finally(() => {
setIsloading(false);
});
}
@@ -84,7 +92,7 @@ export const Login = () => {
<div className="text-red-500">{msg}</div>
<Form.Item>
<Button type="primary" htmlType="submit" className="w-full">
<Button type="primary" htmlType="submit" className="w-full" loading={isLoading}>
{t('auth.loginButtonText')}
</Button>
</Form.Item>

View File

@@ -14,10 +14,11 @@ import * as api from '@/api/storage.ts';
import { client } from '@/lib/websocket.ts';
type ImagesProps = {
cdrom: boolean;
setIsMounted: (isMounted: boolean) => void;
};
export const Images = ({ setIsMounted }: ImagesProps) => {
export const Images = ({ cdrom, setIsMounted }: ImagesProps) => {
const { t } = useTranslation();
const [notify, contextHolder] = notification.useNotification();
@@ -77,7 +78,7 @@ export const Images = ({ setIsMounted }: ImagesProps) => {
const filename = mountedImage === image ? '' : image;
api
.mountImage(filename)
.mountImage(filename, cdrom)
.then((rsp) => {
if (rsp.code !== 0) {
openNotification();

View File

@@ -1,11 +1,11 @@
import { useEffect, useState } from 'react';
import { Divider, Popover } from 'antd';
import { Divider, Popover, Switch, Tooltip } from 'antd';
import clsx from 'clsx';
import { DiscIcon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { useMediaQuery } from 'react-responsive';
import { getMountedImage } from '@/api/storage.ts';
import { getCdRom, getMountedImage } from '@/api/storage.ts';
import { Images } from './images.tsx';
import { Tips } from './tips.tsx';
@@ -16,24 +16,40 @@ export const Image = () => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [isMounted, setIsMounted] = useState(false);
const [cdrom, setCdrom] = useState(false);
useEffect(() => {
getMountedImage().then((rsp) => {
if (rsp.code !== 0) return;
setIsMounted(!!rsp.data?.file);
});
getCdRom().then((rsp) => {
if (rsp.code !== 0) return;
setCdrom(rsp.data?.cdrom === 1);
});
}, []);
const content = (
<div className="min-w-[300px]">
<div className="flex items-center justify-between px-1">
<span className="text-base font-bold text-neutral-300">{t('image.title')}</span>
<Tips />
<div className="flex items-center space-x-1">
<span className="text-base font-bold text-neutral-300">{t('image.title')}</span>
<Tips />
</div>
<Tooltip title="是否以 CD-ROM 模式挂载镜像" placement="bottom">
<div className="flex items-center space-x-2">
<span className="text-xs text-neutral-400">CD-ROM</span>
<Switch size="small" checked={cdrom} onChange={(checked) => setCdrom(checked)}></Switch>
</div>
</Tooltip>
</div>
<Divider style={{ margin: '10px 0 15px 0' }} />
{isPopoverOpen && <Images setIsMounted={setIsMounted} />}
{isPopoverOpen && <Images cdrom={cdrom} setIsMounted={setIsMounted} />}
</div>
);

View File

@@ -51,13 +51,13 @@ export const Tips = () => {
return (
<>
<div
className="flex cursor-pointer items-center space-x-1 text-neutral-400"
className="flex cursor-pointer items-center space-x-1 text-neutral-400 hover:text-blue-400"
onClick={() => setIsModalOpen(true)}
>
<CircleHelpIcon size={16} />
<span className="text-sm text-neutral-500 hover:text-neutral-400">
{t('image.tips.title')}
</span>
{/*<span className="text-sm text-neutral-500 hover:text-neutral-400">*/}
{/* {t('image.tips.title')}*/}
{/*</span>*/}
</div>
<Modal

View File

@@ -68,7 +68,7 @@ export const Update = ({ setIsLocked }: UpdateProps) => {
setErrMsg('');
window.location.reload();
}, 10000);
}, 12000);
});
}
@@ -114,6 +114,17 @@ export const Update = ({ setIsLocked }: UpdateProps) => {
)}
{status === 'failed' && <Result subTitle={errMsg} />}
<div className="flex justify-center">
<Button
type="link"
size="small"
href="https://github.com/sipeed/NanoKVM/blob/main/CHANGELOG.md"
target="_blank"
>
CHANGELOG
</Button>
</div>
</>
);
};