diff --git a/src/backend/database/db/index.ts b/src/backend/database/db/index.ts index 463a2cb3..4db2ceb2 100644 --- a/src/backend/database/db/index.ts +++ b/src/backend/database/db/index.ts @@ -671,6 +671,12 @@ const migrateSchema = () => { `); } catch (createError) { databaseLogger.warn("Failed to create network_topology table", { + error: createError instanceof Error ? createError.message : String(createError), + }); + } + } + + try { sqlite.prepare("SELECT id FROM host_access LIMIT 1").get(); } catch { try { diff --git a/src/backend/database/db/schema.ts b/src/backend/database/db/schema.ts index b3e0c327..70393d47 100644 --- a/src/backend/database/db/schema.ts +++ b/src/backend/database/db/schema.ts @@ -301,6 +301,14 @@ export const networkTopology = sqliteTable("network_topology", { .notNull() .references(() => users.id, { onDelete: "cascade" }), topology: text("topology"), + createdAt: text("created_at") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), + updatedAt: text("updated_at") + .notNull() + .default(sql`CURRENT_TIMESTAMP`), +}); + export const hostAccess = sqliteTable("host_access", { id: integer("id").primaryKey({ autoIncrement: true }), hostId: integer("host_id") diff --git a/src/backend/ssh/server-stats.ts b/src/backend/ssh/server-stats.ts index f9e20f8a..c0b7c11a 100644 --- a/src/backend/ssh/server-stats.ts +++ b/src/backend/ssh/server-stats.ts @@ -1803,6 +1803,10 @@ async function collectMetrics(host: SSHHostWithCredentials): Promise<{ } catch (e) { statsLogger.debug("Failed to collect ports metrics", { operation: "ports_metrics_failed", + error: e instanceof Error ? e.message : String(e), + }); + } + let firewall: { type: "iptables" | "nftables" | "none"; status: "active" | "inactive" | "unknown"; diff --git a/src/backend/utils/user-data-import.ts b/src/backend/utils/user-data-import.ts index ab161e2c..9b1f4aad 100644 --- a/src/backend/utils/user-data-import.ts +++ b/src/backend/utils/user-data-import.ts @@ -194,7 +194,7 @@ class UserDataImport { continue; } - const newHostData = { + const newHostData: Record = { ...host, userId: targetUserId, updatedAt: new Date().toISOString(), @@ -204,14 +204,14 @@ class UserDataImport { newHostData.createdAt = new Date().toISOString(); } - let processedHostData = newHostData; + let processedHostData: Record = newHostData; if (options.userDataKey) { processedHostData = DataCrypto.encryptRecord( "ssh_data", newHostData, targetUserId, options.userDataKey, - ); + ) as Record; } delete processedHostData.id; @@ -275,7 +275,7 @@ class UserDataImport { continue; } - const newCredentialData = { + const newCredentialData: Record = { ...credential, userId: targetUserId, updatedAt: new Date().toISOString(), @@ -287,14 +287,14 @@ class UserDataImport { newCredentialData.createdAt = new Date().toISOString(); } - let processedCredentialData = newCredentialData; + let processedCredentialData: Record = newCredentialData; if (options.userDataKey) { processedCredentialData = DataCrypto.encryptRecord( "ssh_credentials", newCredentialData, targetUserId, options.userDataKey, - ); + ) as Record; } delete processedCredentialData.id; diff --git a/src/locales/en.json b/src/locales/en.json index 9781e412..bf3c0ba1 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1740,6 +1740,7 @@ "state": "State", "process": "Process", "noData": "No listening ports data" + }, "firewall": { "title": "Firewall", "active": "Active", diff --git a/src/types/stats-widgets.ts b/src/types/stats-widgets.ts index 31477eb2..ef777a4e 100644 --- a/src/types/stats-widgets.ts +++ b/src/types/stats-widgets.ts @@ -21,7 +21,7 @@ export interface ListeningPort { export interface PortsMetrics { source: "ss" | "netstat" | "none"; ports: ListeningPort[]; - | "firewall"; +} export interface FirewallRule { chain: string; diff --git a/src/ui/desktop/apps/HostManagerApp.tsx b/src/ui/desktop/apps/HostManagerApp.tsx index fce7e0df..5d5e746f 100644 --- a/src/ui/desktop/apps/HostManagerApp.tsx +++ b/src/ui/desktop/apps/HostManagerApp.tsx @@ -1,4 +1,4 @@ -import { HostManager } from "@/ui/desktop/apps/host-manager/HostManager"; +import { HostManager } from "@/ui/desktop/apps/host-manager/hosts/HostManager.tsx"; import React from "react"; const HostManagerApp: React.FC = () => { diff --git a/src/ui/desktop/apps/features/server-stats/ServerStats.tsx b/src/ui/desktop/apps/features/server-stats/ServerStats.tsx index 20ab7472..48f9f654 100644 --- a/src/ui/desktop/apps/features/server-stats/ServerStats.tsx +++ b/src/ui/desktop/apps/features/server-stats/ServerStats.tsx @@ -270,7 +270,8 @@ export function ServerStats({ case "ports": return ( - + ); + case "firewall": return ( diff --git a/src/ui/desktop/navigation/AppView.tsx b/src/ui/desktop/navigation/AppView.tsx index 5fcb0618..775aef16 100644 --- a/src/ui/desktop/navigation/AppView.tsx +++ b/src/ui/desktop/navigation/AppView.tsx @@ -361,6 +361,7 @@ export function AppView({ rightSidebarOpen={rightSidebarOpen} rightSidebarWidth={rightSidebarWidth} isStandalone={true} + /> ) : t.type === "tunnel" ? (