Migrate everytihng into the main-axios and update the routing to fix localhost issues.

This commit is contained in:
LukeGus
2025-08-25 18:00:34 -05:00
parent d4dccdb574
commit b9bd00f86e
7 changed files with 190 additions and 94 deletions

View File

@@ -4,13 +4,10 @@ import {Homepage} from "@/ui/Homepage/Homepage.tsx"
import {AppView} from "@/ui/Navigation/AppView.tsx" import {AppView} from "@/ui/Navigation/AppView.tsx"
import {HostManager} from "@/ui/apps/Host Manager/HostManager.tsx" import {HostManager} from "@/ui/apps/Host Manager/HostManager.tsx"
import {TabProvider, useTabs} from "@/ui/Navigation/Tabs/TabContext.tsx" import {TabProvider, useTabs} from "@/ui/Navigation/Tabs/TabContext.tsx"
import axios from "axios"
import {TopNavbar} from "@/ui/Navigation/TopNavbar.tsx"; import {TopNavbar} from "@/ui/Navigation/TopNavbar.tsx";
import { AdminSettings } from "@/ui/Admin/AdminSettings"; import { AdminSettings } from "@/ui/Admin/AdminSettings";
import { Toaster } from "@/components/ui/sonner"; import { Toaster } from "@/components/ui/sonner";
import { getUserInfo } from "@/ui/main-axios.ts";
const apiBase = import.meta.env.DEV ? "http://localhost:8081/users" : "/users";
const API = axios.create({baseURL: apiBase});
function getCookie(name: string) { function getCookie(name: string) {
return document.cookie.split('; ').reduce((r, v) => { return document.cookie.split('; ').reduce((r, v) => {
@@ -39,11 +36,11 @@ function AppContent() {
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
if (jwt) { if (jwt) {
setAuthLoading(true); setAuthLoading(true);
API.get("/me", {headers: {Authorization: `Bearer ${jwt}`}}) getUserInfo()
.then((meRes) => { .then((meRes) => {
setIsAuthenticated(true); setIsAuthenticated(true);
setIsAdmin(!!meRes.data.is_admin); setIsAdmin(!!meRes.is_admin);
setUsername(meRes.data.username || null); setUsername(meRes.username || null);
}) })
.catch((err) => { .catch((err) => {
setIsAuthenticated(false); setIsAuthenticated(false);

View File

@@ -16,10 +16,16 @@ import {
TableRow, TableRow,
} from "@/components/ui/table.tsx"; } from "@/components/ui/table.tsx";
import {Shield, Trash2, Users} from "lucide-react"; import {Shield, Trash2, Users} from "lucide-react";
import axios from "axios"; import {
getOIDCConfig,
const apiBase = import.meta.env.DEV ? "http://localhost:8081/users" : "/users"; getRegistrationAllowed,
const API = axios.create({baseURL: apiBase}); getUserList,
updateRegistrationAllowed,
updateOIDCConfig,
makeUserAdmin,
removeAdminStatus,
deleteUser
} from "@/ui/main-axios.ts";
function getCookie(name: string) { function getCookie(name: string) {
return document.cookie.split('; ').reduce((r, v) => { return document.cookie.split('; ').reduce((r, v) => {
@@ -67,9 +73,9 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
React.useEffect(() => { React.useEffect(() => {
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
if (!jwt) return; if (!jwt) return;
API.get("/oidc-config", {headers: {Authorization: `Bearer ${jwt}`}}) getOIDCConfig()
.then(res => { .then(res => {
if (res.data) setOidcConfig(res.data); if (res) setOidcConfig(res);
}) })
.catch(() => { .catch(() => {
}); });
@@ -77,10 +83,10 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
}, []); }, []);
React.useEffect(() => { React.useEffect(() => {
API.get("/registration-allowed") getRegistrationAllowed()
.then(res => { .then(res => {
if (typeof res?.data?.allowed === 'boolean') { if (typeof res?.allowed === 'boolean') {
setAllowRegistration(res.data.allowed); setAllowRegistration(res.allowed);
} }
}) })
.catch(() => { .catch(() => {
@@ -92,8 +98,8 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
if (!jwt) return; if (!jwt) return;
setUsersLoading(true); setUsersLoading(true);
try { try {
const response = await API.get("/list", {headers: {Authorization: `Bearer ${jwt}`}}); const response = await getUserList();
setUsers(response.data.users); setUsers(response.users);
} finally { } finally {
setUsersLoading(false); setUsersLoading(false);
} }
@@ -103,7 +109,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
setRegLoading(true); setRegLoading(true);
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.patch("/registration-allowed", {allowed: checked}, {headers: {Authorization: `Bearer ${jwt}`}}); await updateRegistrationAllowed(checked);
setAllowRegistration(checked); setAllowRegistration(checked);
} finally { } finally {
setRegLoading(false); setRegLoading(false);
@@ -126,7 +132,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.post("/oidc-config", oidcConfig, {headers: {Authorization: `Bearer ${jwt}`}}); await updateOIDCConfig(oidcConfig);
setOidcSuccess("OIDC configuration updated successfully!"); setOidcSuccess("OIDC configuration updated successfully!");
} catch (err: any) { } catch (err: any) {
setOidcError(err?.response?.data?.error || "Failed to update OIDC configuration"); setOidcError(err?.response?.data?.error || "Failed to update OIDC configuration");
@@ -147,7 +153,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
setMakeAdminSuccess(null); setMakeAdminSuccess(null);
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.post("/make-admin", {username: newAdminUsername.trim()}, {headers: {Authorization: `Bearer ${jwt}`}}); await makeUserAdmin(newAdminUsername.trim());
setMakeAdminSuccess(`User ${newAdminUsername} is now an admin`); setMakeAdminSuccess(`User ${newAdminUsername} is now an admin`);
setNewAdminUsername(""); setNewAdminUsername("");
fetchUsers(); fetchUsers();
@@ -162,7 +168,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
if (!confirm(`Remove admin status from ${username}?`)) return; if (!confirm(`Remove admin status from ${username}?`)) return;
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.post("/remove-admin", {username}, {headers: {Authorization: `Bearer ${jwt}`}}); await removeAdminStatus(username);
fetchUsers(); fetchUsers();
} catch { } catch {
} }
@@ -172,7 +178,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
if (!confirm(`Delete user ${username}? This cannot be undone.`)) return; if (!confirm(`Delete user ${username}? This cannot be undone.`)) return;
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.delete("/delete-user", {headers: {Authorization: `Bearer ${jwt}`}, data: {username}}); await deleteUser(username);
fetchUsers(); fetchUsers();
} catch { } catch {
} }

View File

@@ -1,9 +1,9 @@
import React, {useEffect, useState} from "react"; import React, {useEffect, useState} from "react";
import {HomepageAuth} from "@/ui/Homepage/HomepageAuth.tsx"; import {HomepageAuth} from "@/ui/Homepage/HomepageAuth.tsx";
import axios from "axios";
import {HomepageUpdateLog} from "@/ui/Homepage/HompageUpdateLog.tsx"; import {HomepageUpdateLog} from "@/ui/Homepage/HompageUpdateLog.tsx";
import {HomepageAlertManager} from "@/ui/Homepage/HomepageAlertManager.tsx"; import {HomepageAlertManager} from "@/ui/Homepage/HomepageAlertManager.tsx";
import {Button} from "@/components/ui/button.tsx"; import {Button} from "@/components/ui/button.tsx";
import { getUserInfo, getDatabaseHealth } from "@/ui/main-axios.ts";
interface HomepageProps { interface HomepageProps {
onSelectView: (view: string) => void; onSelectView: (view: string) => void;
@@ -25,12 +25,6 @@ function setCookie(name: string, value: string, days = 7) {
document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/`; document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/`;
} }
const apiBase = import.meta.env.DEV ? "http://localhost:8081/users" : "/users";
const API = axios.create({
baseURL: apiBase,
});
export function Homepage({ export function Homepage({
onSelectView, onSelectView,
isAuthenticated, isAuthenticated,
@@ -53,13 +47,13 @@ export function Homepage({
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
if (jwt) { if (jwt) {
Promise.all([ Promise.all([
API.get("/me", {headers: {Authorization: `Bearer ${jwt}`}}), getUserInfo(),
API.get("/db-health") getDatabaseHealth()
]) ])
.then(([meRes]) => { .then(([meRes]) => {
setIsAdmin(!!meRes.data.is_admin); setIsAdmin(!!meRes.is_admin);
setUsername(meRes.data.username || null); setUsername(meRes.username || null);
setUserId(meRes.data.userId || null); setUserId(meRes.userId || null);
setDbError(null); setDbError(null);
}) })
.catch((err) => { .catch((err) => {

View File

@@ -1,7 +1,7 @@
import React, {useEffect, useState} from "react"; import React, {useEffect, useState} from "react";
import {HomepageAlertCard} from "./HomepageAlertCard.tsx"; import {HomepageAlertCard} from "./HomepageAlertCard.tsx";
import {Button} from "@/components/ui/button.tsx"; import {Button} from "@/components/ui/button.tsx";
import axios from "axios"; import { getUserAlerts, dismissAlert } from "@/ui/main-axios.ts";
interface TermixAlert { interface TermixAlert {
id: string; id: string;
@@ -19,12 +19,6 @@ interface AlertManagerProps {
loggedIn: boolean; loggedIn: boolean;
} }
const apiBase = import.meta.env.DEV ? "http://localhost:8081/alerts" : "/alerts";
const API = axios.create({
baseURL: apiBase,
});
export function HomepageAlertManager({userId, loggedIn}: AlertManagerProps): React.ReactElement { export function HomepageAlertManager({userId, loggedIn}: AlertManagerProps): React.ReactElement {
const [alerts, setAlerts] = useState<TermixAlert[]>([]); const [alerts, setAlerts] = useState<TermixAlert[]>([]);
const [currentAlertIndex, setCurrentAlertIndex] = useState(0); const [currentAlertIndex, setCurrentAlertIndex] = useState(0);
@@ -44,9 +38,9 @@ export function HomepageAlertManager({userId, loggedIn}: AlertManagerProps): Rea
setError(null); setError(null);
try { try {
const response = await API.get(`/user/${userId}`); const response = await getUserAlerts(userId);
const userAlerts = response.data.alerts || []; const userAlerts = response.alerts || [];
const sortedAlerts = userAlerts.sort((a: TermixAlert, b: TermixAlert) => { const sortedAlerts = userAlerts.sort((a: TermixAlert, b: TermixAlert) => {
const priorityOrder = {critical: 4, high: 3, medium: 2, low: 1}; const priorityOrder = {critical: 4, high: 3, medium: 2, low: 1};
@@ -73,10 +67,7 @@ export function HomepageAlertManager({userId, loggedIn}: AlertManagerProps): Rea
if (!userId) return; if (!userId) return;
try { try {
const response = await API.post('/dismiss', { await dismissAlert(userId, alertId);
userId,
alertId
});
setAlerts(prev => { setAlerts(prev => {
const newAlerts = prev.filter(alert => alert.id !== alertId); const newAlerts = prev.filter(alert => alert.id !== alertId);

View File

@@ -2,7 +2,7 @@ import React, {useEffect, useState} from "react";
import {Alert, AlertDescription, AlertTitle} from "@/components/ui/alert.tsx"; import {Alert, AlertDescription, AlertTitle} from "@/components/ui/alert.tsx";
import {Button} from "@/components/ui/button.tsx"; import {Button} from "@/components/ui/button.tsx";
import {Separator} from "@/components/ui/separator.tsx"; import {Separator} from "@/components/ui/separator.tsx";
import axios from "axios"; import { getReleasesRSS, getVersionInfo } from "@/ui/main-axios.ts";
interface HomepageUpdateLogProps extends React.ComponentProps<"div"> { interface HomepageUpdateLogProps extends React.ComponentProps<"div"> {
loggedIn: boolean; loggedIn: boolean;
@@ -50,12 +50,6 @@ interface VersionResponse {
cache_age?: number; cache_age?: number;
} }
const apiBase = import.meta.env.DEV ? "http://localhost:8081" : "";
const API = axios.create({
baseURL: apiBase,
});
export function HomepageUpdateLog({loggedIn}: HomepageUpdateLogProps) { export function HomepageUpdateLog({loggedIn}: HomepageUpdateLogProps) {
const [releases, setReleases] = useState<RSSResponse | null>(null); const [releases, setReleases] = useState<RSSResponse | null>(null);
const [versionInfo, setVersionInfo] = useState<VersionResponse | null>(null); const [versionInfo, setVersionInfo] = useState<VersionResponse | null>(null);
@@ -66,12 +60,12 @@ export function HomepageUpdateLog({loggedIn}: HomepageUpdateLogProps) {
if (loggedIn) { if (loggedIn) {
setLoading(true); setLoading(true);
Promise.all([ Promise.all([
API.get('/releases/rss?per_page=100'), getReleasesRSS(100),
API.get('/version/') getVersionInfo()
]) ])
.then(([releasesRes, versionRes]) => { .then(([releasesRes, versionRes]) => {
setReleases(releasesRes.data); setReleases(releasesRes);
setVersionInfo(versionRes.data); setVersionInfo(versionRes);
setError(null); setError(null);
}) })
.catch(err => { .catch(err => {

View File

@@ -45,11 +45,18 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table.tsx"; } from "@/components/ui/table.tsx";
import axios from "axios";
import {Card} from "@/components/ui/card.tsx"; import {Card} from "@/components/ui/card.tsx";
import {FolderCard} from "@/ui/Navigation/Hosts/FolderCard.tsx"; import {FolderCard} from "@/ui/Navigation/Hosts/FolderCard.tsx";
import {getSSHHosts} from "@/ui/main-axios.ts"; import {getSSHHosts} from "@/ui/main-axios.ts";
import {useTabs} from "@/ui/Navigation/Tabs/TabContext.tsx"; import {useTabs} from "@/ui/Navigation/Tabs/TabContext.tsx";
import {
getOIDCConfig,
getUserList,
makeUserAdmin,
removeAdminStatus,
deleteUser,
deleteAccount
} from "@/ui/main-axios.ts";
interface SSHHost { interface SSHHost {
id: number; id: number;
@@ -95,11 +102,7 @@ function getCookie(name: string) {
}, ""); }, "");
} }
const apiBase = import.meta.env.DEV ? "http://localhost:8081/users" : "/users";
const API = axios.create({
baseURL: apiBase,
});
export function LeftSidebar({ export function LeftSidebar({
onSelectView, onSelectView,
@@ -162,9 +165,9 @@ export function LeftSidebar({
if (adminSheetOpen) { if (adminSheetOpen) {
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
if (jwt && isAdmin) { if (jwt && isAdmin) {
API.get("/oidc-config").then(res => { getOIDCConfig().then(res => {
if (res.data) { if (res) {
setOidcConfig(res.data); setOidcConfig(res);
} }
}).catch((error) => { }).catch((error) => {
}); });
@@ -308,10 +311,7 @@ export function LeftSidebar({
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.delete("/delete-account", { await deleteAccount(deletePassword);
headers: {Authorization: `Bearer ${jwt}`},
data: {password: deletePassword}
});
handleLogout(); handleLogout();
} catch (err: any) { } catch (err: any) {
@@ -329,12 +329,10 @@ export function LeftSidebar({
setUsersLoading(true); setUsersLoading(true);
try { try {
const response = await API.get("/list", { const response = await getUserList();
headers: {Authorization: `Bearer ${jwt}`} setUsers(response.users);
});
setUsers(response.data.users);
const adminUsers = response.data.users.filter((user: any) => user.is_admin); const adminUsers = response.users.filter((user: any) => user.is_admin);
setAdminCount(adminUsers.length); setAdminCount(adminUsers.length);
} catch (err: any) { } catch (err: any) {
} finally { } finally {
@@ -350,10 +348,8 @@ export function LeftSidebar({
} }
try { try {
const response = await API.get("/list", { const response = await getUserList();
headers: {Authorization: `Bearer ${jwt}`} const adminUsers = response.users.filter((user: any) => user.is_admin);
});
const adminUsers = response.data.users.filter((user: any) => user.is_admin);
setAdminCount(adminUsers.length); setAdminCount(adminUsers.length);
} catch (err: any) { } catch (err: any) {
} }
@@ -373,10 +369,7 @@ export function LeftSidebar({
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.post("/make-admin", await makeUserAdmin(newAdminUsername.trim());
{username: newAdminUsername.trim()},
{headers: {Authorization: `Bearer ${jwt}`}}
);
setMakeAdminSuccess(`User ${newAdminUsername} is now an admin`); setMakeAdminSuccess(`User ${newAdminUsername} is now an admin`);
setNewAdminUsername(""); setNewAdminUsername("");
fetchUsers(); fetchUsers();
@@ -396,10 +389,7 @@ export function LeftSidebar({
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.post("/remove-admin", await removeAdminStatus(username);
{username},
{headers: {Authorization: `Bearer ${jwt}`}}
);
fetchUsers(); fetchUsers();
} catch (err: any) { } catch (err: any) {
} }
@@ -414,10 +404,7 @@ export function LeftSidebar({
const jwt = getCookie("jwt"); const jwt = getCookie("jwt");
try { try {
await API.delete("/delete-user", { await deleteUser(username);
headers: {Authorization: `Bearer ${jwt}`},
data: {username}
});
fetchUsers(); fetchUsers();
} catch (err: any) { } catch (err: any) {
} }

View File

@@ -1,4 +1,4 @@
import axios, { AxiosError, AxiosInstance } from 'axios'; import axios, { AxiosError, type AxiosInstance } from 'axios';
// ============================================================================ // ============================================================================
// TYPES & INTERFACES // TYPES & INTERFACES
@@ -201,7 +201,10 @@ function createApiInstance(baseURL: string): AxiosInstance {
// API INSTANCES // API INSTANCES
// ============================================================================ // ============================================================================
const isDev = process.env.NODE_ENV === 'development' || window.location.hostname === 'localhost'; // Check if we're in development mode (Vite dev server) or if we're accessing via a specific port
// that indicates we're using nginx proxy (not localhost:3000 or similar dev ports)
const isDev = process.env.NODE_ENV === 'development' &&
(window.location.port === '3000' || window.location.port === '5173' || window.location.port === '');
// SSH Host Management API (port 8081) // SSH Host Management API (port 8081)
export const sshHostApi = createApiInstance( export const sshHostApi = createApiInstance(
@@ -820,4 +823,128 @@ export async function getOIDCAuthorizeUrl(): Promise<OIDCAuthorize> {
} catch (error) { } catch (error) {
handleApiError(error, 'get OIDC authorize URL'); handleApiError(error, 'get OIDC authorize URL');
} }
}
// ============================================================================
// USER MANAGEMENT
// ============================================================================
export async function getUserList(): Promise<{ users: UserInfo[] }> {
try {
const response = await authApi.get('/list');
return response.data;
} catch (error) {
handleApiError(error, 'fetch user list');
}
}
export async function makeUserAdmin(username: string): Promise<any> {
try {
const response = await authApi.post('/make-admin', { username });
return response.data;
} catch (error) {
handleApiError(error, 'make user admin');
}
}
export async function removeAdminStatus(username: string): Promise<any> {
try {
const response = await authApi.post('/remove-admin', { username });
return response.data;
} catch (error) {
handleApiError(error, 'remove admin status');
}
}
export async function deleteUser(username: string): Promise<any> {
try {
const response = await authApi.delete('/delete-user', { data: { username } });
return response.data;
} catch (error) {
handleApiError(error, 'delete user');
}
}
export async function deleteAccount(password: string): Promise<any> {
try {
const response = await authApi.delete('/delete-account', { data: { password } });
return response.data;
} catch (error) {
handleApiError(error, 'delete account');
}
}
export async function updateRegistrationAllowed(allowed: boolean): Promise<any> {
try {
const response = await authApi.patch('/registration-allowed', { allowed });
return response.data;
} catch (error) {
handleApiError(error, 'update registration allowed');
}
}
export async function updateOIDCConfig(config: any): Promise<any> {
try {
const response = await authApi.post('/oidc-config', config);
return response.data;
} catch (error) {
handleApiError(error, 'update OIDC config');
}
}
// ============================================================================
// ALERTS
// ============================================================================
export async function getUserAlerts(userId: string): Promise<{ alerts: any[] }> {
try {
const response = await authApi.get(`/alerts/user/${userId}`);
return response.data;
} catch (error) {
handleApiError(error, 'fetch user alerts');
}
}
export async function dismissAlert(userId: string, alertId: string): Promise<any> {
try {
const response = await authApi.post('/alerts/dismiss', { userId, alertId });
return response.data;
} catch (error) {
handleApiError(error, 'dismiss alert');
}
}
// ============================================================================
// UPDATES & RELEASES
// ============================================================================
export async function getReleasesRSS(perPage: number = 100): Promise<any> {
try {
const response = await authApi.get(`/releases/rss?per_page=${perPage}`);
return response.data;
} catch (error) {
handleApiError(error, 'fetch releases RSS');
}
}
export async function getVersionInfo(): Promise<any> {
try {
const response = await authApi.get('/version/');
return response.data;
} catch (error) {
handleApiError(error, 'fetch version info');
}
}
// ============================================================================
// DATABASE HEALTH
// ============================================================================
export async function getDatabaseHealth(): Promise<any> {
try {
const response = await authApi.get('/db-health');
return response.data;
} catch (error) {
handleApiError(error, 'check database health');
}
} }