mirror of
https://github.com/sipeed/NanoKVM.git
synced 2026-09-11 00:22:56 -05:00
feat: support downloading image from online URL feat: add keyboard shortcut Ctrl+Alt+Del fix: fix the CSRF issue perf: add an option to configure custom ICE servers perf: removed unnecessary modifications to DNS configuration perf: add an SSH enable/disable toggle in the web UI perf: add a Tailscale enable/disable toggle in the web UI perf: download Tailscale installation package from the official source perf: automatic enable/disable GOMEMLIMIT on tailscale start/stop perf: add JWT configuration perf: implement secure password storage using bcrypt hashing perf: implement integrity checks for online updates refactor: refactor HDMI module and remove the dependency libmaixcam_lib.so refactor: web terminal use pty instead of SSH refactor: move Tailscale APIs from the network module to the extensions module
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { useState } from 'react';
|
|
import { DownloadOutlined, InfoCircleOutlined } from '@ant-design/icons';
|
|
import { Button, Card, Result } from 'antd';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import * as api from '@/api/extensions/tailscale.ts';
|
|
|
|
type InstallProps = {
|
|
setIsLocked: (setIsLocked: boolean) => void;
|
|
onSuccess: () => void;
|
|
};
|
|
|
|
export const Install = ({ setIsLocked, onSuccess }: InstallProps) => {
|
|
const { t } = useTranslation();
|
|
|
|
const [state, setState] = useState('');
|
|
|
|
function install() {
|
|
if (state === 'installing') return;
|
|
setState('installing');
|
|
setIsLocked(true);
|
|
|
|
api
|
|
.install()
|
|
.then((rsp) => {
|
|
if (rsp.code !== 0) {
|
|
setState('failed');
|
|
return;
|
|
}
|
|
|
|
onSuccess();
|
|
})
|
|
.finally(() => {
|
|
setState('');
|
|
setIsLocked(false);
|
|
});
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{state !== 'failed' ? (
|
|
<Result
|
|
icon={<DownloadOutlined />}
|
|
subTitle={t('settings.tailscale.notInstall')}
|
|
extra={
|
|
<Button type="primary" size="large" loading={state === 'installing'} onClick={install}>
|
|
{state === 'installing'
|
|
? t('settings.tailscale.installing')
|
|
: t('settings.tailscale.install')}
|
|
</Button>
|
|
}
|
|
/>
|
|
) : (
|
|
<Result
|
|
status="warning"
|
|
title={t('settings.tailscale.failed')}
|
|
subTitle={t('settings.tailscale.retry')}
|
|
icon={<InfoCircleOutlined />}
|
|
extra={
|
|
<Card styles={{ body: { padding: 0 } }}>
|
|
<ul className="list-decimal text-left font-mono text-sm text-neutral-300">
|
|
<li>
|
|
{t('settings.tailscale.download')}
|
|
<a
|
|
className="px-1"
|
|
href="https://pkgs.tailscale.com/stable/tailscale_latest_riscv64.tgz"
|
|
target="_blank"
|
|
>
|
|
{t('settings.tailscale.package')}
|
|
</a>
|
|
{t('settings.tailscale.unzip')}
|
|
</li>
|
|
<li>{t('settings.tailscale.upTailscale')}</li>
|
|
<li>{t('settings.tailscale.upTailscaled')}</li>
|
|
<li>{t('settings.tailscale.refresh')}</li>
|
|
</ul>
|
|
</Card>
|
|
}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
};
|