General bug fixes in terminal and file manager and fixed credential errors in production

This commit is contained in:
LukeGus
2025-09-28 23:54:12 -05:00
parent 63e776f183
commit 144171d1fa
15 changed files with 139 additions and 41 deletions

View File

@@ -1217,7 +1217,7 @@ async function deploySSHKeyToHost(
await new Promise<void>((resolveAdd, rejectAdd) => {
const addTimeout = setTimeout(() => {
rejectAdd(new Error("Key add timeout"));
}, 10000);
}, 30000);
let actualPublicKey = publicKey;
try {

View File

@@ -86,7 +86,9 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
const [currentHost, setCurrentHost] = useState<SSHHost | null>(
initialHost || null,
);
const [currentPath, setCurrentPath] = useState("/");
const [currentPath, setCurrentPath] = useState(
initialHost?.defaultPath || "/"
);
const [files, setFiles] = useState<FileItem[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [sshSessionId, setSshSessionId] = useState<string | null>(null);
@@ -754,8 +756,14 @@ function FileManagerContent({ initialHost, onClose }: FileManagerProps) {
await recordRecentFile(file);
const windowCount = Date.now() % 10;
const offsetX = 120 + windowCount * 30;
const offsetY = 120 + windowCount * 30;
const baseOffsetX = 120 + windowCount * 30;
const baseOffsetY = 120 + windowCount * 30;
const maxOffsetX = Math.max(0, window.innerWidth - 800 - 100);
const maxOffsetY = Math.max(0, window.innerHeight - 600 - 100);
const offsetX = Math.min(baseOffsetX, maxOffsetX);
const offsetY = Math.min(baseOffsetY, maxOffsetY);
const windowTitle = file.name;

View File

@@ -332,7 +332,7 @@ export function DraggableWindow({
</div>
<div
className="flex-1 overflow-auto"
className="flex-1 overflow-hidden"
style={{ height: "calc(100% - 40px)" }}
>
{children}

View File

@@ -90,6 +90,7 @@ interface FileViewerProps {
isEditable?: boolean;
onContentChange?: (content: string) => void;
onSave?: (content: string) => void;
onRevert?: () => void;
onDownload?: () => void;
onMediaDimensionsChange?: (dimensions: {
width: number;
@@ -304,6 +305,7 @@ export function FileViewer({
isEditable = false,
onContentChange,
onSave,
onRevert,
onDownload,
onMediaDimensionsChange,
}: FileViewerProps) {
@@ -352,7 +354,12 @@ export function FileViewer({
} else {
setShowLargeFileWarning(false);
}
}, [content, savedContent, fileTypeInfo.type, isLargeFile, forceShowAsText]);
if (fileTypeInfo.type === "image" && file.name.toLowerCase().endsWith('.svg') && content) {
setImageLoading(false);
setImageLoadError(false);
}
}, [content, savedContent, fileTypeInfo.type, isLargeFile, forceShowAsText, file.name]);
const handleContentChange = (newContent: string) => {
setEditedContent(newContent);
@@ -365,9 +372,12 @@ export function FileViewer({
};
const handleRevert = () => {
setEditedContent(savedContent);
setHasChanges(false);
onContentChange?.(savedContent);
if (onRevert) {
onRevert();
} else {
setEditedContent(savedContent);
setHasChanges(false);
}
};
useEffect(() => {
@@ -696,6 +706,16 @@ export function FileViewer({
</Button>
)}
</div>
) : file.name.toLowerCase().endsWith('.svg') ? (
<div
className="max-w-full max-h-full flex items-center justify-center"
style={{ maxHeight: "calc(100vh - 200px)" }}
dangerouslySetInnerHTML={{ __html: content }}
onLoad={() => {
setImageLoading(false);
setImageLoadError(false);
}}
/>
) : (
<PhotoProvider maskOpacity={0.7}>
<PhotoView src={`data:image/*;base64,${content}`}>

View File

@@ -211,6 +211,37 @@ export function FileWindow({
loadFileContent();
}, [file, sshSessionId, sshHost]);
const handleRevert = async () => {
const loadFileContent = async () => {
if (file.type !== "file") return;
try {
setIsLoading(true);
await ensureSSHConnection();
const response = await readSSHFile(sshSessionId, file.path);
const fileContent = response.content || "";
setContent(fileContent);
setPendingContent("");
if (!file.size) {
const contentSize = new Blob([fileContent]).size;
file.size = contentSize;
}
} catch (error: any) {
console.error("Failed to load file content:", error);
toast.error(
`${t("fileManager.failedToLoadFile")}: ${error.message || t("fileManager.unknownError")}`,
);
} finally {
setIsLoading(false);
}
};
loadFileContent();
};
const handleSave = async (newContent: string) => {
try {
setIsLoading(true);
@@ -252,17 +283,20 @@ export function FileWindow({
if (autoSaveTimerRef.current) {
clearTimeout(autoSaveTimerRef.current);
autoSaveTimerRef.current = null;
}
autoSaveTimerRef.current = setTimeout(async () => {
try {
await handleSave(newContent);
toast.success(t("fileManager.fileAutoSaved"));
} catch (error) {
console.error("Auto-save failed:", error);
toast.error(t("fileManager.autoSaveFailed"));
}
}, 60000);
if (newContent !== content) {
autoSaveTimerRef.current = setTimeout(async () => {
try {
await handleSave(newContent);
toast.success(t("fileManager.fileAutoSaved"));
} catch (error) {
console.error("Auto-save failed:", error);
toast.error(t("fileManager.autoSaveFailed"));
}
}, 60000);
}
};
useEffect(() => {
@@ -363,6 +397,7 @@ export function FileWindow({
content={pendingContent || content}
savedContent={content}
isLoading={isLoading}
onRevert={handleRevert}
isEditable={isEditable}
onContentChange={handleContentChange}
onSave={(newContent) => handleSave(newContent)}

View File

@@ -79,7 +79,6 @@ export function TerminalWindow({
minWidth={600}
minHeight={400}
onClose={handleClose}
onMinimize={handleMinimize}
onMaximize={handleMaximize}
onFocus={handleFocus}
isMaximized={currentWindow.isMaximized}

View File

@@ -40,9 +40,15 @@ export function WindowManager({ children }: WindowManagerProps) {
const id = `window-${++windowCounter.current}`;
const zIndex = ++nextZIndex.current;
const offset = (windows.length % 5) * 30;
const adjustedX = windowData.x + offset;
const adjustedY = windowData.y + offset;
const offset = (windows.length % 5) * 20;
let adjustedX = windowData.x + offset;
let adjustedY = windowData.y + offset;
const maxX = Math.max(0, window.innerWidth - windowData.width - 20);
const maxY = Math.max(0, window.innerHeight - windowData.height - 20);
adjustedX = Math.max(20, Math.min(adjustedX, maxX));
adjustedY = Math.max(20, Math.min(adjustedY, maxY));
const newWindow: WindowInstance = {
...windowData,

View File

@@ -75,10 +75,6 @@ export function useFileSelection() {
}, [selectedFiles]);
const setSelection = useCallback((files: FileItem[]) => {
console.log(
"Setting selection to:",
files.map((f) => f.name),
);
setSelectedFiles(files);
}, []);

View File

@@ -692,10 +692,10 @@ export const Terminal = forwardRef<any, SSHTerminalProps>(function SSHTerminal(
}, [splitScreen, isVisible, terminal]);
return (
<div className="h-full w-full m-1 relative">
<div className="h-full w-full relative">
<div
ref={xtermRef}
className={`h-full w-full transition-opacity duration-200 ${visible && isVisible && !isConnecting ? "opacity-100" : "opacity-0"} overflow-hidden`}
className={`h-full w-full transition-opacity duration-200 ${visible && isVisible && !isConnecting ? "opacity-100" : "opacity-0"}`}
onClick={() => {
if (terminal && !splitScreen) {
terminal.focus();

View File

@@ -143,11 +143,12 @@ function AppContent() {
isAdmin={isAdmin}
username={username}
>
{showTerminalView && (
<div className="h-screen w-full visible pointer-events-auto static overflow-hidden">
<AppView isTopbarOpen={isTopbarOpen} />
</div>
)}
<div
className="h-screen w-full visible pointer-events-auto static overflow-hidden"
style={{ display: showTerminalView ? "block" : "none" }}
>
<AppView isTopbarOpen={isTopbarOpen} />
</div>
{showHome && (
<div className="h-screen w-full visible pointer-events-auto static overflow-hidden">

View File

@@ -23,6 +23,7 @@ import {
getCookie,
getServerConfig,
isElectron,
logoutUser,
} from "../../main-axios.ts";
import { ServerConfig as ServerConfigComponent } from "@/ui/Desktop/Electron Only/ServerConfig.tsx";
@@ -101,6 +102,17 @@ export function HomepageAuth({
setInternalLoggedIn(loggedIn);
}, [loggedIn]);
useEffect(() => {
const clearJWTOnLoad = async () => {
try {
await logoutUser();
} catch (error) {
}
};
clearJWTOnLoad();
}, []);
useEffect(() => {
getRegistrationAllowed().then((res) => {
setRegistrationAllowed(res.allowed);

View File

@@ -140,10 +140,10 @@ export function AppView({
const isFileManagerTab = mainTab.type === "file_manager";
styles[mainTab.id] = {
position: "absolute",
top: isFileManagerTab ? 0 : 2,
left: isFileManagerTab ? 0 : 2,
right: isFileManagerTab ? 0 : 2,
bottom: isFileManagerTab ? 0 : 2,
top: isFileManagerTab ? 0 : 4,
left: isFileManagerTab ? 0 : 4,
right: isFileManagerTab ? 0 : 4,
bottom: isFileManagerTab ? 0 : 4,
zIndex: 20,
display: "block",
pointerEvents: "auto",
@@ -156,10 +156,10 @@ export function AppView({
if (rect && parentRect) {
styles[t.id] = {
position: "absolute",
top: rect.top - parentRect.top + HEADER_H + 2,
left: rect.left - parentRect.left + 2,
width: rect.width - 4,
height: rect.height - HEADER_H - 4,
top: rect.top - parentRect.top + HEADER_H + 4,
left: rect.left - parentRect.left + 4,
width: rect.width - 8,
height: rect.height - HEADER_H - 8,
zIndex: 20,
display: "block",
pointerEvents: "auto",

View File

@@ -21,6 +21,7 @@ import {
verifyTOTPLogin,
setCookie,
getCookie,
logoutUser,
} from "@/ui/main-axios.ts";
import { PasswordInput } from "@/components/ui/password-input.tsx";
@@ -88,6 +89,18 @@ export function HomepageAuth({
setInternalLoggedIn(loggedIn);
}, [loggedIn]);
useEffect(() => {
const clearJWTOnLoad = async () => {
try {
await logoutUser();
} catch (error) {
console.log("JWT cleanup on HomepageAuth load:", error);
}
};
clearJWTOnLoad();
}, []);
useEffect(() => {
getRegistrationAllowed().then((res) => {
setRegistrationAllowed(res.allowed);