feat: support URL routes to open terminal directly (#156) #503
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -194,7 +194,7 @@ class UserDataImport {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newHostData = {
|
||||
const newHostData: Record<string, unknown> = {
|
||||
...host,
|
||||
userId: targetUserId,
|
||||
updatedAt: new Date().toISOString(),
|
||||
@@ -204,14 +204,14 @@ class UserDataImport {
|
||||
newHostData.createdAt = new Date().toISOString();
|
||||
}
|
||||
|
||||
let processedHostData = newHostData;
|
||||
let processedHostData: Record<string, unknown> = newHostData;
|
||||
if (options.userDataKey) {
|
||||
processedHostData = DataCrypto.encryptRecord(
|
||||
"ssh_data",
|
||||
newHostData,
|
||||
targetUserId,
|
||||
options.userDataKey,
|
||||
);
|
||||
) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
delete processedHostData.id;
|
||||
@@ -275,7 +275,7 @@ class UserDataImport {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newCredentialData = {
|
||||
const newCredentialData: Record<string, unknown> = {
|
||||
...credential,
|
||||
userId: targetUserId,
|
||||
updatedAt: new Date().toISOString(),
|
||||
@@ -287,14 +287,14 @@ class UserDataImport {
|
||||
newCredentialData.createdAt = new Date().toISOString();
|
||||
}
|
||||
|
||||
let processedCredentialData = newCredentialData;
|
||||
let processedCredentialData: Record<string, unknown> = newCredentialData;
|
||||
if (options.userDataKey) {
|
||||
processedCredentialData = DataCrypto.encryptRecord(
|
||||
"ssh_credentials",
|
||||
newCredentialData,
|
||||
targetUserId,
|
||||
options.userDataKey,
|
||||
);
|
||||
) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
delete processedCredentialData.id;
|
||||
|
||||
@@ -1740,6 +1740,7 @@
|
||||
"state": "State",
|
||||
"process": "Process",
|
||||
"noData": "No listening ports data"
|
||||
},
|
||||
"firewall": {
|
||||
"title": "Firewall",
|
||||
"active": "Active",
|
||||
|
||||
@@ -21,7 +21,7 @@ export interface ListeningPort {
|
||||
export interface PortsMetrics {
|
||||
source: "ss" | "netstat" | "none";
|
||||
ports: ListeningPort[];
|
||||
| "firewall";
|
||||
}
|
||||
|
||||
export interface FirewallRule {
|
||||
chain: string;
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -270,7 +270,8 @@ export function ServerStats({
|
||||
case "ports":
|
||||
return (
|
||||
<PortsWidget metrics={metrics} metricsHistory={metricsHistory} />
|
||||
|
||||
);
|
||||
|
||||
case "firewall":
|
||||
return (
|
||||
<FirewallWidget metrics={metrics} metricsHistory={metricsHistory} />
|
||||
|
||||
@@ -361,6 +361,7 @@ export function AppView({
|
||||
rightSidebarOpen={rightSidebarOpen}
|
||||
rightSidebarWidth={rightSidebarWidth}
|
||||
isStandalone={true}
|
||||
/>
|
||||
) : t.type === "tunnel" ? (
|
||||
<TunnelManager
|
||||
hostConfig={t.hostConfig}
|
||||
|
||||
Reference in New Issue
Block a user