feat(ui): add type filter toggles

This commit is contained in:
2026-02-18 23:13:28 -08:00
commit a4cff9894c
14457 changed files with 2204835 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
import { Client } from 'ssh2';
export interface SSHConnectionConfig {
host: string;
port?: number;
username: string;
privateKey?: string;
password?: string;
}
export interface DockerContainer {
name: string;
image: string;
status: string;
ports: string[];
created: string;
}
export interface HostInfo {
name: string;
ip: string;
online: boolean;
containers: DockerContainer[];
cpuUsage?: number;
memoryUsage?: number;
uptime?: string;
error?: string;
}
async function connectSSH(config: SSHConnectionConfig): Promise<Client> {
return new Promise((resolve, reject) => {
const conn = new Client();
conn.on('ready', () => resolve(conn));
conn.on('error', (err) => reject(err));
conn.connect({
host: config.host,
port: config.port || 22,
username: config.username,
privateKey: config.privateKey,
password: config.password,
readyTimeout: 10000,
});
});
}
async function execSSH(conn: Client, command: string): Promise<string> {
return new Promise((resolve, reject) => {
conn.exec(command, (err, stream) => {
if (err) {
reject(err);
return;
}
let output = '';
stream.on('close', () => resolve(output));
stream.on('data', (data: Buffer) => { output += data.toString(); });
stream.stderr.on('data', (data: Buffer) => { output += data.toString(); });
});
});
}
export async function discoverHostViaSSH(
hostName: string,
ip: string,
sshConfig?: SSHConnectionConfig
): Promise<HostInfo> {
const defaultConfig: SSHConnectionConfig = {
host: ip,
username: 'bear',
privateKey: require('fs').readFileSync(require('os').homedir() + '/.ssh/id_ed25519'),
};
const config = sshConfig || defaultConfig;
try {
const conn = await connectSSH(config);
const dockerPsCmd = `docker ps --format '{{.Names}}|{{.Image}}|{{.Status}}|{{.Ports}}|{{.CreatedAt}}'`;
const dockerPsOutput = await execSSH(conn, dockerPsCmd);
const containers: DockerContainer[] = dockerPsOutput
.trim()
.split('\n')
.filter(line => line.trim())
.map(line => {
const [name, image, status, ports, created] = line.split('|');
return {
name: name.trim(),
image: image.trim(),
status: status.trim(),
ports: ports.trim() ? ports.trim().split(', ') : [],
created: created.trim(),
};
});
conn.end();
return {
name: hostName,
ip: ip,
online: true,
containers,
};
} catch (error: any) {
return {
name: hostName,
ip: ip,
online: false,
containers: [],
error: error.message || 'Connection failed',
};
}
}
export async function discoverAllHostsSSH(
hosts: { name: string; ip: string }[]
): Promise<HostInfo[]> {
const results = await Promise.all(
hosts.map(host => discoverHostViaSSH(host.name, host.ip))
);
return results;
}
if (require.main === module) {
const hosts = [
{ name: 'ubuntu', ip: '192.168.50.61' },
{ name: 'grizzley', ip: '192.168.50.84' },
{ name: 'truenas', ip: '192.168.50.12' },
];
discoverAllHostsSSH(hosts).then(results => {
console.log(JSON.stringify(results, null, 2));
}).catch(console.error);
}