feat: support URL routes to open terminal directly (#156) #503

Merged
ZacharyZcR merged 3 commits from feat/url-terminal-route into dev-1.10.1 2026-01-13 05:57:10 +00:00
9 changed files with 30 additions and 9 deletions
Showing only changes of commit 3922a82dfc - Show all commits

View File

@@ -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 {

View File

@@ -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")

View File

@@ -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";

View File

@@ -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;

View File

@@ -1740,6 +1740,7 @@
"state": "State",
"process": "Process",
"noData": "No listening ports data"
},
"firewall": {
"title": "Firewall",
"active": "Active",

View File

@@ -21,7 +21,7 @@ export interface ListeningPort {
export interface PortsMetrics {
source: "ss" | "netstat" | "none";
ports: ListeningPort[];
| "firewall";
}
export interface FirewallRule {
chain: string;

View File

@@ -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 = () => {

View File

@@ -270,7 +270,8 @@ export function ServerStats({
case "ports":
return (
<PortsWidget metrics={metrics} metricsHistory={metricsHistory} />
);
case "firewall":
return (
<FirewallWidget metrics={metrics} metricsHistory={metricsHistory} />

View File

@@ -361,6 +361,7 @@ export function AppView({
rightSidebarOpen={rightSidebarOpen}
rightSidebarWidth={rightSidebarWidth}
isStandalone={true}
/>
) : t.type === "tunnel" ? (
<TunnelManager
hostConfig={t.hostConfig}