Update App version to 0.0.2

This commit is contained in:
luckfox-eng29
2025-09-16 11:03:46 +08:00
parent 8fbd6bcf0d
commit 15d276652c
45 changed files with 3347 additions and 252 deletions

View File

@@ -109,6 +109,11 @@ export function Dialog({ onClose }: { onClose: () => void }) {
function handleStorageMount(fileName: string, mode: RemoteVirtualMediaState["mode"]) {
console.log(`Mounting ${fileName} as ${mode}`);
if (!fileName.endsWith(".iso") && !fileName.endsWith(".img")) {
triggerError("Only ISO and IMG files are supported");
return;
}
setMountInProgress(true);
send("mountWithStorage", { filename: fileName, mode }, async resp => {
if ("error" in resp) triggerError(resp.error.message);
@@ -136,6 +141,11 @@ export function Dialog({ onClose }: { onClose: () => void }) {
function handleSDStorageMount(fileName: string, mode: RemoteVirtualMediaState["mode"]) {
console.log(`Mounting ${fileName} as ${mode}`);
if (!fileName.endsWith(".iso") && !fileName.endsWith(".img")) {
triggerError("Only ISO and IMG files are supported");
return;
}
setMountInProgress(true);
send("mountWithSDStorage", { filename: fileName, mode }, async resp => {
if ("error" in resp) triggerError(resp.error.message);
@@ -407,7 +417,7 @@ function ModeSelectionView({
<div
className="relative z-50 flex flex-col items-start p-4 select-none"
onClick={() =>
disabled ? null : setSelectedMode(mode as "browser" | "url" | "device")
disabled ? null : setSelectedMode(mode as "browser" | "url" | "device" | "sd")
}
>
<div>
@@ -1069,6 +1079,7 @@ function SDFileView({
const [selected, setSelected] = useState<string | null>(null);
const [usbMode, setUsbMode] = useState<RemoteVirtualMediaState["mode"]>("CDROM");
const [currentPage, setCurrentPage] = useState(1);
const [loading, setLoading] = useState(false);
const filesPerPage = 5;
const [send] = useJsonRpc();
@@ -1195,17 +1206,37 @@ function SDFileView({
const handleNextPage = () => {
setCurrentPage(prev => Math.min(prev + 1, totalPages));
};
function handleResetSDStorage() {
async function handleResetSDStorage() {
setLoading(true);
send("resetSDStorage", {}, res => {
console.log("Reset SD storage response:", res);
if ("error" in res) {
notifications.error(`Failed to reset SD card`);
setLoading(false);
return;
}
});
});
await new Promise(resolve => setTimeout(resolve, 2000));
setLoading(false);
syncStorage();
}
async function handleUnmountSDStorage() {
setLoading(true);
send("unmountSDStorage", {}, res => {
console.log("Unmount SD response:", res);
if ("error" in res) {
notifications.error(`Failed to unmount SD card`);
setLoading(false);
return;
}
});
await new Promise(resolve => setTimeout(resolve, 2000));
setLoading(false);
syncStorage();
}
if (sdMountStatus && sdMountStatus !== "ok") {
return (
@@ -1223,6 +1254,7 @@ function SDFileView({
: "SD card mount failed"}
<Button
size="XS"
disabled={loading}
theme="light"
LeadingIcon={LuRefreshCw}
onClick={handleResetSDStorage}
@@ -1268,6 +1300,7 @@ function SDFileView({
<div>
<Button
size="SM"
disabled={loading}
theme="primary"
text="Upload a new image"
onClick={() => onNewImageClick()}
@@ -1312,14 +1345,14 @@ function SDFileView({
theme="light"
text="Previous"
onClick={handlePreviousPage}
disabled={currentPage === 1}
disabled={currentPage === 1 || loading}
/>
<Button
size="XS"
theme="light"
text="Next"
onClick={handleNextPage}
disabled={currentPage === totalPages}
disabled={currentPage === totalPages || loading}
/>
</div>
</div>
@@ -1344,7 +1377,7 @@ function SDFileView({
<Button size="MD" theme="blank" text="Back" onClick={() => onBack()} />
<Button
size="MD"
disabled={selected === null || mountInProgress}
disabled={selected === null || mountInProgress || loading}
theme="primary"
text="Mount File"
loading={mountInProgress}
@@ -1412,6 +1445,7 @@ function SDFileView({
>
<Button
size="MD"
disabled={loading}
theme="light"
fullWidth
text="Upload a new image"
@@ -1419,6 +1453,24 @@ function SDFileView({
/>
</div>
)}
<div
className="w-full animate-fadeIn opacity-0"
style={{
animationDuration: "0.7s",
animationDelay: "0.25s",
}}
>
<Button
size="MD"
disabled={loading}
theme="light"
fullWidth
text="Unmount SD Card"
onClick={() => handleUnmountSDStorage()}
className="text-red-500 dark:text-red-400"
/>
</div>
</div>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,8 @@ import { CloudState } from "./adopt";
import { useVpnStore } from "@/hooks/stores";
import Checkbox from "../components/Checkbox";
import { LogDialog } from "../components/LogDialog";
export interface TailScaleResponse {
state: string;
loginUrl: string;
@@ -35,6 +37,11 @@ export interface ZeroTierResponse {
ip: string;
}
export interface FrpcResponse {
running: boolean;
}
export interface TLSState {
mode: "self-signed" | "custom" | "disabled";
certificate?: string;
@@ -83,6 +90,11 @@ export default function SettingsAccessIndexRoute() {
const [tempNetworkID, setTempNetworkID] = useState("");
const [isDisconnecting, setIsDisconnecting] = useState(false);
const [frpcToml, setFrpcToml] = useState<string>("");
const [frpcLog, setFrpcLog] = useState<string>("");
const [showFrpcLogModal, setShowFrpcLogModal] = useState(false);
const [frpcStatus, setFrpcRunningStatus] = useState<FrpcResponse>({ running: false });
const getTLSState = useCallback(() => {
send("getTLSState", {}, resp => {
@@ -262,6 +274,77 @@ export default function SettingsAccessIndexRoute() {
});
},[send, zeroTierNetworkID]);
const handleStartFrpc = useCallback(() => {
send("startFrpc", { frpcToml }, resp => {
if ("error" in resp) {
notifications.error(
`Failed to start frpc: ${resp.error.data || "Unknown error"}`,
);
setFrpcRunningStatus({ running: false });
return;
}
notifications.success("frpc started");
setFrpcRunningStatus({ running: true });
});
}, [send, frpcToml]);
const handleStopFrpc = useCallback(() => {
send("stopFrpc", { frpcToml }, resp => {
if ("error" in resp) {
notifications.error(
`Failed to stop frpc: ${resp.error.data || "Unknown error"}`,
);
return;
}
notifications.success("frpc stopped");
setFrpcRunningStatus({ running: false });
});
}, [send]);
const handleGetFrpcLog = useCallback(() => {
send("getFrpcLog", {}, resp => {
if ("error" in resp) {
notifications.error(
`Failed to get frpc log: ${resp.error.data || "Unknown error"}`,
);
setFrpcLog("");
return;
}
setFrpcLog(resp.result as string);
setShowFrpcLogModal(true);
});
}, [send]);
const getFrpcToml = useCallback(() => {
send("getFrpcToml", {}, resp => {
if ("error" in resp) {
notifications.error(
`Failed to get frpc toml: ${resp.error.data || "Unknown error"}`,
);
setFrpcToml("");
return;
}
setFrpcToml(resp.result as string);
});
}, [send]);
const getFrpcStatus = useCallback(() => {
send("getFrpcStatus", {}, resp => {
if ("error" in resp) {
notifications.error(
`Failed to get frpc status: ${resp.error.data || "Unknown error"}`,
);
return;
}
setFrpcRunningStatus(resp.result as FrpcResponse);
});
}, [send]);
useEffect(() => {
getFrpcStatus();
getFrpcToml();
}, [getFrpcStatus, getFrpcToml]);
return (
<div className="space-y-4">
<SettingsPageHeader
@@ -399,16 +482,6 @@ export default function SettingsAccessIndexRoute() {
badge="Experimental"
description="Connect to TailScale VPN network"
>
<div className="space-y-4">
{ ((tailScaleConnectionState === "disconnected") || (tailScaleConnectionState === "closed")) && (
<Button
size="SM"
theme="light"
text="Enable TailScale"
onClick={handleTailScaleLogin}
/>
)}
</div>
</SettingsItem>
<SettingsItem
title=""
@@ -425,6 +498,21 @@ export default function SettingsAccessIndexRoute() {
}}
/>
</SettingsItem>
<SettingsItem
title=""
description=""
>
<div className="space-y-4">
{ ((tailScaleConnectionState === "disconnected") || (tailScaleConnectionState === "closed")) && (
<Button
size="SM"
theme="light"
text="Enable"
onClick={handleTailScaleLogin}
/>
)}
</div>
</SettingsItem>
</div>
<div className="space-y-4">
@@ -558,7 +646,58 @@ export default function SettingsAccessIndexRoute() {
)}
</div>
<div className="space-y-4">
<SettingsItem
title="Frp"
description="Connect to Frp Server"
/>
<div className="space-y-4">
<TextAreaWithLabel
label="Edit frpc.toml"
placeholder="Enter frpc settings"
value={frpcToml || ""}
rows={3}
onChange={e => setFrpcToml(e.target.value)}
/>
<div className="flex items-center gap-x-2">
{frpcStatus.running ? (
<div className="flex items-center gap-x-2">
<Button
size="SM"
theme="danger"
text="Stop frpc"
onClick={handleStopFrpc}
/>
<Button
size="SM"
theme="light"
text="Log"
onClick={handleGetFrpcLog}
/>
</div>
) : (
<Button
size="SM"
theme="primary"
text="Start frpc"
onClick={handleStartFrpc}
/>
)}
</div>
</div>
</div>
</div>
<LogDialog
open={showFrpcLogModal}
onClose={() => {
setShowFrpcLogModal(false);
}}
title="Frpc Log"
description={frpcLog}
/>
</div>
);
}

View File

@@ -5,13 +5,11 @@ import { SettingsItem } from "@routes/devices.$id.settings";
import { BacklightSettings, useSettingsStore } from "@/hooks/stores";
import { useJsonRpc } from "@/hooks/useJsonRpc";
import { SelectMenuBasic } from "@components/SelectMenuBasic";
import { UsbDeviceSetting } from "@components/UsbDeviceSetting";
import { InputField } from "@/components/InputField";
import { Button, LinkButton } from "@/components/Button";
import notifications from "../notifications";
import { UsbInfoSetting } from "../components/UsbInfoSetting";
import { FeatureFlag } from "../components/FeatureFlag";
import { UsbEpModeSetting } from "@components/UsbEpModeSetting";
export default function SettingsHardwareRoute() {
const [send] = useJsonRpc();
@@ -333,13 +331,9 @@ export default function SettingsHardwareRoute() {
</div>
<FeatureFlag minAppVersion="0.3.8">
<UsbDeviceSetting />
</FeatureFlag>
<FeatureFlag minAppVersion="0.3.8">
<UsbInfoSetting />
</FeatureFlag>
<UsbEpModeSetting />
{/*<UsbDeviceSetting /> */}
{/*<UsbInfoSetting /> */}
</div>
);
}

View File

@@ -40,16 +40,9 @@ const streamQualityOptions = [
{ value: "0.1", label: "Low" },
];
const audioModeOptions = [
{ value: "disabled", label: "Disabled"},
{ value: "usb", label: "USB"},
//{ value: "hdmi", label: "HDMI"},
]
export default function SettingsVideoRoute() {
const [send] = useJsonRpc();
const [streamQuality, setStreamQuality] = useState("1");
const [audioMode, setAudioMode] = useState("disabled");
const [customEdidValue, setCustomEdidValue] = useState<string | null>(null);
const [edid, setEdid] = useState<string | null>(null);
@@ -62,11 +55,6 @@ export default function SettingsVideoRoute() {
const setVideoContrast = useSettingsStore(state => state.setVideoContrast);
useEffect(() => {
send("getAudioMode", {}, resp => {
if ("error" in resp) return;
setAudioMode(String(resp.result));
});
send("getStreamQualityFactor", {}, resp => {
if ("error" in resp) return;
setStreamQuality(String(resp.result));
@@ -95,21 +83,7 @@ export default function SettingsVideoRoute() {
}
});
}, [send]);
const handleAudioModeChange = (mode: string) => {
send("setAudioMode", { mode }, resp => {
if ("error" in resp) {
notifications.error(
`Failed to set Audio Mode: ${resp.error.data || "Unknown error"}`,
);
return;
}
notifications.success(`Audio Mode set to ${audioModeOptions.find(x => x.value === mode )?.label}.It takes effect after refreshing the page`);
setAudioMode(mode);
});
};
const handleStreamQualityChange = (factor: string) => {
send("setStreamQualityFactor", { factor: Number(factor) }, resp => {
if ("error" in resp) {
@@ -149,20 +123,6 @@ export default function SettingsVideoRoute() {
<div className="space-y-4">
<div className="space-y-4">
<SettingsItem
title="Audio Mode"
badge="Experimental"
description="Set the working mode of the audio"
>
<SelectMenuBasic
size="SM"
label=""
value={audioMode}
options={audioModeOptions}
onChange={e => handleAudioModeChange(e.target.value)}
/>
</SettingsItem>
<SettingsItem
title="Stream Quality"
description="Adjust the quality of the video stream"

View File

@@ -233,7 +233,8 @@ export default function KvmIdRoute() {
const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:";
const { sendMessage, getWebSocket } = useWebSocket(
`${wsProtocol}//${window.location.host}/webrtc/signaling/client?id=${params.id}`,
//`${wsProtocol}//${window.location.host}/webrtc/signaling/client?id=${params.id}`,
`${wsProtocol}//${window.location.host}/webrtc/signaling/client`,
{
heartbeat: true,
retryOnError: true,
@@ -362,9 +363,18 @@ export default function KvmIdRoute() {
setLoadingMessage("Creating peer connection...");
pc = new RTCPeerConnection({
// We only use STUN or TURN servers if we're in the cloud
...(isInCloud && iceConfig?.iceServers
? { iceServers: [iceConfig?.iceServers] }
: {}),
//...(isInCloud && iceConfig?.iceServers
// ? { iceServers: [iceConfig?.iceServers] }
// : {}),
...(iceConfig?.iceServers
? { iceServers: [iceConfig?.iceServers] }
: {
iceServers: [
{
urls: ['stun:stun.l.google.com:19302']
}
]
}),
});
setPeerConnectionState(pc.connectionState);