From 81d1db09e4fe462c116542cea1edcf849c75c8cf Mon Sep 17 00:00:00 2001 From: LukeGus Date: Thu, 14 Aug 2025 01:24:05 -0500 Subject: [PATCH] Initial UI commit for 1.3 --- .env | 2 +- src/App.tsx | 123 +++++++++++++----- src/apps/SSH/Manager/SSHManagerSidebar.tsx | 59 --------- src/apps/Template/Template.tsx | 18 --- src/apps/Template/TemplateSidebar.tsx | 58 --------- src/components/ui/sidebar.tsx | 4 +- src/{apps => ui}/Homepage/Homepage.tsx | 53 ++++---- .../Homepage/HomepageAlertCard.tsx} | 8 +- .../Homepage/HomepageAlertManager.tsx} | 11 +- src/{apps => ui}/Homepage/HomepageAuth.tsx | 11 +- .../Homepage/HompageUpdateLog.tsx | 0 .../Navigation/Sidebar.tsx} | 39 ++++-- .../SSH/Config Editor/ConfigCodeEditor.tsx | 0 .../SSH/Config Editor/ConfigEditor.tsx | 12 +- .../SSH/Config Editor/ConfigEditorSidebar.tsx | 2 +- .../Config Editor/ConfigFileSidebarViewer.tsx | 0 .../SSH/Config Editor/ConfigHomeView.tsx | 0 .../SSH/Config Editor/ConfigTabList.tsx | 0 .../SSH/Config Editor/ConfigTopbar.tsx | 0 src/{apps => ui}/SSH/Manager/SSHManager.tsx | 25 ++-- .../SSH/Manager/SSHManagerHostEditor.tsx | 21 ++- .../SSH/Manager/SSHManagerHostViewer.tsx | 2 +- src/{apps => ui}/SSH/Terminal/Terminal.tsx | 4 +- .../SSH/Terminal/TerminalComponent.tsx | 0 .../SSH/Terminal/TerminalSidebar.tsx | 2 +- .../SSH/Terminal/TerminalTabList.tsx | 0 .../SSH/Terminal/TerminalTopbar.tsx | 2 +- src/{apps => ui}/SSH/Tunnel/SSHTunnel.tsx | 6 +- .../SSH/Tunnel/SSHTunnelObject.tsx | 0 .../SSH/Tunnel/SSHTunnelSidebar.tsx | 0 .../SSH/Tunnel/SSHTunnelViewer.tsx | 0 src/{apps => ui}/SSH/ssh-axios.ts | 0 tsconfig.app.json | 6 - 33 files changed, 196 insertions(+), 272 deletions(-) delete mode 100644 src/apps/SSH/Manager/SSHManagerSidebar.tsx delete mode 100644 src/apps/Template/Template.tsx delete mode 100644 src/apps/Template/TemplateSidebar.tsx rename src/{apps => ui}/Homepage/Homepage.tsx (64%) rename src/{apps/Homepage/AlertCard.tsx => ui/Homepage/HomepageAlertCard.tsx} (95%) rename src/{apps/Homepage/AlertManager.tsx => ui/Homepage/HomepageAlertManager.tsx} (95%) rename src/{apps => ui}/Homepage/HomepageAuth.tsx (99%) rename src/{apps => ui}/Homepage/HompageUpdateLog.tsx (100%) rename src/{apps/Homepage/HomepageSidebar.tsx => ui/Navigation/Sidebar.tsx} (97%) rename src/{apps => ui}/SSH/Config Editor/ConfigCodeEditor.tsx (100%) rename src/{apps => ui}/SSH/Config Editor/ConfigEditor.tsx (98%) rename src/{apps => ui}/SSH/Config Editor/ConfigEditorSidebar.tsx (99%) rename src/{apps => ui}/SSH/Config Editor/ConfigFileSidebarViewer.tsx (100%) rename src/{apps => ui}/SSH/Config Editor/ConfigHomeView.tsx (100%) rename src/{apps => ui}/SSH/Config Editor/ConfigTabList.tsx (100%) rename src/{apps => ui}/SSH/Config Editor/ConfigTopbar.tsx (100%) rename src/{apps => ui}/SSH/Manager/SSHManager.tsx (77%) rename src/{apps => ui}/SSH/Manager/SSHManagerHostEditor.tsx (98%) rename src/{apps => ui}/SSH/Manager/SSHManagerHostViewer.tsx (99%) rename src/{apps => ui}/SSH/Terminal/Terminal.tsx (99%) rename src/{apps => ui}/SSH/Terminal/TerminalComponent.tsx (100%) rename src/{apps => ui}/SSH/Terminal/TerminalSidebar.tsx (99%) rename src/{apps => ui}/SSH/Terminal/TerminalTabList.tsx (100%) rename src/{apps => ui}/SSH/Terminal/TerminalTopbar.tsx (97%) rename src/{apps => ui}/SSH/Tunnel/SSHTunnel.tsx (96%) rename src/{apps => ui}/SSH/Tunnel/SSHTunnelObject.tsx (100%) rename src/{apps => ui}/SSH/Tunnel/SSHTunnelSidebar.tsx (100%) rename src/{apps => ui}/SSH/Tunnel/SSHTunnelViewer.tsx (100%) rename src/{apps => ui}/SSH/ssh-axios.ts (100%) diff --git a/.env b/.env index 27929cde..07925e7a 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -VERSION=1.1.1 \ No newline at end of file +VERSION=1.3 \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index c4510ae9..26f0717a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,14 +1,64 @@ -import React from "react" +import React, { useState, useEffect } from "react" +import { Sidebar } from "@/ui/Navigation/Sidebar.tsx" +import { Homepage } from "@/ui/Homepage/Homepage.tsx" +import { Terminal } from "@/ui/SSH/Terminal/Terminal.tsx" +import { SSHTunnel } from "@/ui/SSH/Tunnel/SSHTunnel.tsx" +import { ConfigEditor } from "@/ui/SSH/Config Editor/ConfigEditor.tsx" +import { SSHManager } from "@/ui/SSH/Manager/SSHManager.tsx" +import axios from "axios" -import {Homepage} from "@/apps/Homepage/Homepage.tsx" -import {Terminal} from "@/apps/SSH/Terminal/Terminal.tsx" -import {SSHTunnel} from "@/apps/SSH/Tunnel/SSHTunnel.tsx"; -import {ConfigEditor} from "@/apps/SSH/Config Editor/ConfigEditor.tsx"; -import {SSHManager} from "@/apps/SSH/Manager/SSHManager.tsx" +const apiBase = import.meta.env.DEV ? "http://localhost:8081/users" : "/users"; +const API = axios.create({ baseURL: apiBase }); + +function getCookie(name: string) { + return document.cookie.split('; ').reduce((r, v) => { + const parts = v.split('='); + return parts[0] === name ? decodeURIComponent(parts[1]) : r; + }, ""); +} function App() { const [view, setView] = React.useState("homepage") const [mountedViews, setMountedViews] = React.useState>(new Set(["homepage"])) + const [isAuthenticated, setIsAuthenticated] = useState(false) + const [username, setUsername] = useState(null) + const [isAdmin, setIsAdmin] = useState(false) + const [authLoading, setAuthLoading] = useState(true) + + useEffect(() => { + const checkAuth = () => { + const jwt = getCookie("jwt"); + if (jwt) { + setAuthLoading(true); + API.get("/me", {headers: {Authorization: `Bearer ${jwt}`}}) + .then((meRes) => { + setIsAuthenticated(true); + setIsAdmin(!!meRes.data.is_admin); + setUsername(meRes.data.username || null); + }) + .catch((err) => { + setIsAuthenticated(false); + setIsAdmin(false); + setUsername(null); + // Clear invalid JWT + document.cookie = 'jwt=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; + }) + .finally(() => setAuthLoading(false)); + } else { + setIsAuthenticated(false); + setIsAdmin(false); + setUsername(null); + setAuthLoading(false); + } + } + + checkAuth() + + const handleStorageChange = () => checkAuth() + window.addEventListener('storage', handleStorageChange) + + return () => window.removeEventListener('storage', handleStorageChange) + }, []) const handleSelectView = (nextView: string) => { setMountedViews((prev) => { @@ -21,35 +71,38 @@ function App() { } return ( -
-
- {mountedViews.has("homepage") && ( -
- -
- )} - {mountedViews.has("ssh_manager") && ( -
- -
- )} - {mountedViews.has("terminal") && ( -
- -
- )} - {mountedViews.has("tunnel") && ( -
- -
- )} - {mountedViews.has("config_editor") && ( -
- -
- )} -
-
+ + {mountedViews.has("homepage") && ( +
+ +
+ )} + {mountedViews.has("ssh_manager") && ( +
+ +
+ )} + {mountedViews.has("terminal") && ( +
+ +
+ )} + {mountedViews.has("tunnel") && ( +
+ +
+ )} + {mountedViews.has("config_editor") && ( +
+ +
+ )} +
) } diff --git a/src/apps/SSH/Manager/SSHManagerSidebar.tsx b/src/apps/SSH/Manager/SSHManagerSidebar.tsx deleted file mode 100644 index 819830f3..00000000 --- a/src/apps/SSH/Manager/SSHManagerSidebar.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; - -import { - CornerDownLeft -} from "lucide-react" - -import { - Button -} from "@/components/ui/button.tsx" - -import { - Sidebar, - SidebarContent, - SidebarGroup, - SidebarGroupContent, - SidebarGroupLabel, - SidebarMenu, - SidebarMenuItem, SidebarProvider, -} from "@/components/ui/sidebar.tsx" - -import { - Separator, -} from "@/components/ui/separator.tsx" - -interface SidebarProps { - onSelectView: (view: string) => void; -} - -export function SSHManagerSidebar({onSelectView}: SidebarProps): React.ReactElement { - return ( - - - - - - Termix / SSH Manager - - - - - - {/* Sidebar Items */} - - - - - - - - - - - - ) -} \ No newline at end of file diff --git a/src/apps/Template/Template.tsx b/src/apps/Template/Template.tsx deleted file mode 100644 index 09c02a2e..00000000 --- a/src/apps/Template/Template.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import {TemplateSidebar} from "@/apps/Template/TemplateSidebar.tsx"; - -interface ConfigEditorProps { - onSelectView: (view: string) => void; -} - -export function Template({onSelectView}: ConfigEditorProps): React.ReactElement { - return ( -
- - - Template -
- ) -} \ No newline at end of file diff --git a/src/apps/Template/TemplateSidebar.tsx b/src/apps/Template/TemplateSidebar.tsx deleted file mode 100644 index eb4f903b..00000000 --- a/src/apps/Template/TemplateSidebar.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; - -import { - CornerDownLeft -} from "lucide-react" - -import { - Button -} from "@/components/ui/button.tsx" - -import { - Sidebar, - SidebarContent, - SidebarGroup, - SidebarGroupContent, - SidebarGroupLabel, - SidebarMenu, - SidebarMenuItem, SidebarProvider, -} from "@/components/ui/sidebar.tsx" - -import { - Separator, -} from "@/components/ui/separator.tsx" - -interface SidebarProps { - onSelectView: (view: string) => void; -} - -export function TemplateSidebar({onSelectView}: SidebarProps): React.ReactElement { - return ( - - - - - - Termix / Template - - - - - - - - - - - - - - - - - ) -} \ No newline at end of file diff --git a/src/components/ui/sidebar.tsx b/src/components/ui/sidebar.tsx index ad864e24..66aace69 100644 --- a/src/components/ui/sidebar.tsx +++ b/src/components/ui/sidebar.tsx @@ -234,7 +234,7 @@ function Sidebar({ // Adjust the padding for floating and inset variants. variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" - : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l", + : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)", className )} {...props} @@ -242,7 +242,7 @@ function Sidebar({
{children}
diff --git a/src/apps/Homepage/Homepage.tsx b/src/ui/Homepage/Homepage.tsx similarity index 64% rename from src/apps/Homepage/Homepage.tsx rename to src/ui/Homepage/Homepage.tsx index 299203fd..00967404 100644 --- a/src/apps/Homepage/Homepage.tsx +++ b/src/ui/Homepage/Homepage.tsx @@ -1,9 +1,8 @@ -import {HomepageSidebar} from "@/apps/Homepage/HomepageSidebar.tsx"; import React, {useEffect, useState} from "react"; -import {HomepageAuth} from "@/apps/Homepage/HomepageAuth.tsx"; +import {HomepageAuth} from "@/ui/Homepage/HomepageAuth.tsx"; import axios from "axios"; -import {HomepageUpdateLog} from "@/apps/Homepage/HompageUpdateLog.tsx"; -import {AlertManager} from "@/apps/Homepage/AlertManager.tsx"; +import {HomepageUpdateLog} from "@/ui/Homepage/HompageUpdateLog.tsx"; +import {HomepageAlertManager} from "@/ui/Homepage/HomepageAlertManager.tsx"; interface HomepageProps { onSelectView: (view: string) => void; @@ -70,35 +69,27 @@ export function Homepage({onSelectView}: HomepageProps): React.ReactElement { }, []); return ( - -
-
- - -
- - {/* Alert Manager - replaces the old welcome card */} - +
+ +
- + + +
); } \ No newline at end of file diff --git a/src/apps/Homepage/AlertCard.tsx b/src/ui/Homepage/HomepageAlertCard.tsx similarity index 95% rename from src/apps/Homepage/AlertCard.tsx rename to src/ui/Homepage/HomepageAlertCard.tsx index c6850f6e..d2f34722 100644 --- a/src/apps/Homepage/AlertCard.tsx +++ b/src/ui/Homepage/HomepageAlertCard.tsx @@ -1,7 +1,7 @@ import React from "react"; -import {Card, CardContent, CardFooter, CardHeader, CardTitle} from "@/components/ui/card"; -import {Button} from "@/components/ui/button"; -import {Badge} from "@/components/ui/badge"; +import {Card, CardContent, CardFooter, CardHeader, CardTitle} from "@/components/ui/card.tsx"; +import {Button} from "@/components/ui/button.tsx"; +import {Badge} from "@/components/ui/badge.tsx"; import {X, ExternalLink, AlertTriangle, Info, CheckCircle, AlertCircle} from "lucide-react"; interface TermixAlert { @@ -63,7 +63,7 @@ const getTypeBadgeVariant = (type?: string) => { } }; -export function AlertCard({alert, onDismiss, onClose}: AlertCardProps): React.ReactElement { +export function HomepageAlertCard({alert, onDismiss, onClose}: AlertCardProps): React.ReactElement { if (!alert) { return null; } diff --git a/src/apps/Homepage/AlertManager.tsx b/src/ui/Homepage/HomepageAlertManager.tsx similarity index 95% rename from src/apps/Homepage/AlertManager.tsx rename to src/ui/Homepage/HomepageAlertManager.tsx index a9eb0fd1..07772d2a 100644 --- a/src/apps/Homepage/AlertManager.tsx +++ b/src/ui/Homepage/HomepageAlertManager.tsx @@ -1,6 +1,6 @@ import React, {useEffect, useState} from "react"; -import {AlertCard} from "./AlertCard"; -import {Button} from "@/components/ui/button"; +import {HomepageAlertCard} from "./HomepageAlertCard.tsx"; +import {Button} from "@/components/ui/button.tsx"; import axios from "axios"; interface TermixAlert { @@ -25,7 +25,7 @@ const API = axios.create({ baseURL: apiBase, }); -export function AlertManager({userId, loggedIn}: AlertManagerProps): React.ReactElement { +export function HomepageAlertManager({userId, loggedIn}: AlertManagerProps): React.ReactElement { const [alerts, setAlerts] = useState([]); const [currentAlertIndex, setCurrentAlertIndex] = useState(0); const [loading, setLoading] = useState(false); @@ -154,14 +154,12 @@ export function AlertManager({userId, loggedIn}: AlertManagerProps): React.React return (
- {/* Current Alert */} - - {/* Navigation Controls */} {hasMultipleAlerts && (
+ + + - - Termix - - @@ -893,6 +904,14 @@ export function HomepageSidebar({ {children} + + {!isSidebarOpen && ( +
setIsSidebarOpen(true)} + className="absolute top-0 left-0 w-[10px] h-full bg-[#18181b] cursor-pointer z-20 flex items-center justify-center"> + +
+ )}
) } \ No newline at end of file diff --git a/src/apps/SSH/Config Editor/ConfigCodeEditor.tsx b/src/ui/SSH/Config Editor/ConfigCodeEditor.tsx similarity index 100% rename from src/apps/SSH/Config Editor/ConfigCodeEditor.tsx rename to src/ui/SSH/Config Editor/ConfigCodeEditor.tsx diff --git a/src/apps/SSH/Config Editor/ConfigEditor.tsx b/src/ui/SSH/Config Editor/ConfigEditor.tsx similarity index 98% rename from src/apps/SSH/Config Editor/ConfigEditor.tsx rename to src/ui/SSH/Config Editor/ConfigEditor.tsx index 7251ba77..6ac5eb6f 100644 --- a/src/apps/SSH/Config Editor/ConfigEditor.tsx +++ b/src/ui/SSH/Config Editor/ConfigEditor.tsx @@ -1,10 +1,10 @@ import React, {useState, useEffect, useRef} from "react"; -import {ConfigEditorSidebar} from "@/apps/SSH/Config Editor/ConfigEditorSidebar.tsx"; -import {ConfigTabList} from "@/apps/SSH/Config Editor/ConfigTabList.tsx"; -import {ConfigHomeView} from "@/apps/SSH/Config Editor/ConfigHomeView.tsx"; -import {ConfigCodeEditor} from "@/apps/SSH/Config Editor/ConfigCodeEditor.tsx"; +import {ConfigEditorSidebar} from "@/ui/SSH/Config Editor/ConfigEditorSidebar.tsx"; +import {ConfigTabList} from "@/ui/SSH/Config Editor/ConfigTabList.tsx"; +import {ConfigHomeView} from "@/ui/SSH/Config Editor/ConfigHomeView.tsx"; +import {ConfigCodeEditor} from "@/ui/SSH/Config Editor/ConfigCodeEditor.tsx"; import {Button} from '@/components/ui/button.tsx'; -import {ConfigTopbar} from "@/apps/SSH/Config Editor/ConfigTopbar.tsx"; +import {ConfigTopbar} from "@/ui/SSH/Config Editor/ConfigTopbar.tsx"; import {cn} from '@/lib/utils.ts'; import { getConfigEditorRecent, @@ -20,7 +20,7 @@ import { writeSSHFile, getSSHStatus, connectSSH -} from '@/apps/SSH/ssh-axios.ts'; +} from '@/ui/SSH/ssh-axios.ts'; interface Tab { id: string | number; diff --git a/src/apps/SSH/Config Editor/ConfigEditorSidebar.tsx b/src/ui/SSH/Config Editor/ConfigEditorSidebar.tsx similarity index 99% rename from src/apps/SSH/Config Editor/ConfigEditorSidebar.tsx rename to src/ui/SSH/Config Editor/ConfigEditorSidebar.tsx index 571182f3..22579660 100644 --- a/src/apps/SSH/Config Editor/ConfigEditorSidebar.tsx +++ b/src/ui/SSH/Config Editor/ConfigEditorSidebar.tsx @@ -22,7 +22,7 @@ import { getConfigEditorPinned, addConfigEditorPinned, removeConfigEditorPinned -} from '@/apps/SSH/ssh-axios.ts'; +} from '@/ui/SSH/ssh-axios.ts'; interface SSHHost { id: number; diff --git a/src/apps/SSH/Config Editor/ConfigFileSidebarViewer.tsx b/src/ui/SSH/Config Editor/ConfigFileSidebarViewer.tsx similarity index 100% rename from src/apps/SSH/Config Editor/ConfigFileSidebarViewer.tsx rename to src/ui/SSH/Config Editor/ConfigFileSidebarViewer.tsx diff --git a/src/apps/SSH/Config Editor/ConfigHomeView.tsx b/src/ui/SSH/Config Editor/ConfigHomeView.tsx similarity index 100% rename from src/apps/SSH/Config Editor/ConfigHomeView.tsx rename to src/ui/SSH/Config Editor/ConfigHomeView.tsx diff --git a/src/apps/SSH/Config Editor/ConfigTabList.tsx b/src/ui/SSH/Config Editor/ConfigTabList.tsx similarity index 100% rename from src/apps/SSH/Config Editor/ConfigTabList.tsx rename to src/ui/SSH/Config Editor/ConfigTabList.tsx diff --git a/src/apps/SSH/Config Editor/ConfigTopbar.tsx b/src/ui/SSH/Config Editor/ConfigTopbar.tsx similarity index 100% rename from src/apps/SSH/Config Editor/ConfigTopbar.tsx rename to src/ui/SSH/Config Editor/ConfigTopbar.tsx diff --git a/src/apps/SSH/Manager/SSHManager.tsx b/src/ui/SSH/Manager/SSHManager.tsx similarity index 77% rename from src/apps/SSH/Manager/SSHManager.tsx rename to src/ui/SSH/Manager/SSHManager.tsx index 90c11750..7c3348f3 100644 --- a/src/apps/SSH/Manager/SSHManager.tsx +++ b/src/ui/SSH/Manager/SSHManager.tsx @@ -1,9 +1,9 @@ import React, {useState} from "react"; -import {SSHManagerSidebar} from "@/apps/SSH/Manager/SSHManagerSidebar.tsx"; -import {SSHManagerHostViewer} from "@/apps/SSH/Manager/SSHManagerHostViewer.tsx" +import {SSHManagerHostViewer} from "@/ui/SSH/Manager/SSHManagerHostViewer.tsx" import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs.tsx"; import {Separator} from "@/components/ui/separator.tsx"; -import {SSHManagerHostEditor} from "@/apps/SSH/Manager/SSHManagerHostEditor.tsx"; +import {SSHManagerHostEditor} from "@/ui/SSH/Manager/SSHManagerHostEditor.tsx"; +import {useSidebar} from "@/components/ui/sidebar.tsx"; interface ConfigEditorProps { onSelectView: (view: string) => void; @@ -35,6 +35,7 @@ interface SSHHost { export function SSHManager({onSelectView}: ConfigEditorProps): React.ReactElement { const [activeTab, setActiveTab] = useState("host_viewer"); const [editingHost, setEditingHost] = useState(null); + const {state: sidebarState} = useSidebar(); const handleEditHost = (host: SSHHost) => { setEditingHost(host); @@ -55,29 +56,25 @@ export function SSHManager({onSelectView}: ConfigEditorProps): React.ReactElemen return (
- - -
-
- +
+ className={`flex-1 bg-[#18181b] m-[8px] text-white p-4 pt-0 rounded-lg border border-[#303032] flex flex-col min-h-0 ${ + sidebarState === 'collapsed' ? 'ml-6' : '' + }`}> - + Host Viewer {editingHost ? "Edit Host" : "Add Host"} - + - +
- + General @@ -396,7 +396,7 @@ export function SSHManagerHostEditor({editingHost, onFormSubmit}: SSHManagerHost Tunnel Config Editor - + Connection Details
-