Files
Termix/src/types/ui-types.ts
T

470 lines
11 KiB
TypeScript
Raw Normal View History

+5
2026-08-19 14:12:06 -05:00
import type { GuacamoleConfig } from "./guacamole-config.js";
import type { TerminalConfig } from "./index.js";
import type { StatsConfig } from "./stats-widgets.js";
+3
2026-08-06 14:41:39 -05:00
import type { HostAuthOverrides } from "./auth-protocols.js";
2026-05-11 01:23:11 -05:00
export type Host = {
id: string;
name: string;
username: string;
ip: string;
port: number;
folder: string;
+5
2026-08-19 14:12:06 -05:00
/** Sub-host nesting: the id of the host this one is organized under, if any. */
parentHostId?: string | null;
/**
* Sub-hosts nested under this host, populated client-side by buildHostTree.
* A host with children still renders and behaves as a normal, connectable
* HostItem row -- this only adds an expand/collapse chevron for its nested
* children, it never wraps the host in a synthetic folder node.
*/
childHosts?: Host[];
2026-05-11 01:23:11 -05:00
online: boolean;
+5
2026-08-19 14:12:06 -05:00
status?: "online" | "reachable" | "offline" | "unknown";
2026-05-28 22:29:20 -05:00
cpu: number | null;
ram: number | null;
2026-05-11 01:23:11 -05:00
lastAccess: string;
tags?: string[];
2026-06-29 13:28:26 -05:00
authType:
| "password"
| "key"
| "credential"
| "none"
| "opkssh"
| "tailscale"
| "vault"
| "agent";
2026-06-21 15:55:41 -05:00
useWarpgate?: boolean;
+3
2026-08-06 14:41:39 -05:00
shareSshAuth?: boolean;
2026-05-11 01:23:11 -05:00
credentialId?: string;
2026-06-29 13:28:26 -05:00
vaultProfileId?: string;
2026-05-28 22:29:20 -05:00
overrideCredentialUsername?: boolean;
2026-05-11 01:23:11 -05:00
password?: string;
2026-06-04 15:16:53 -04:00
hasPassword?: boolean;
sudoPassword?: string;
hasSudoPassword?: boolean;
2026-05-28 22:29:20 -05:00
hasKey?: boolean;
hasKeyPassword?: boolean;
2026-05-11 01:23:11 -05:00
key?: string;
keyPassword?: string;
keyType?: string;
notes?: string;
macAddress?: string;
2026-06-21 15:55:41 -05:00
wolBroadcastAddress?: string;
2026-05-11 01:23:11 -05:00
pin?: boolean;
+5
2026-08-19 14:12:06 -05:00
sortOrder?: number | null;
2026-05-11 01:23:11 -05:00
enableTerminal: boolean;
+2
2026-06-16 15:59:53 -05:00
enableCommandHistory: boolean;
+5
2026-08-19 14:12:06 -05:00
enableSessionLogging?: boolean;
allowSessionSharing?: boolean;
/** Stable identity across a desktop/server sync pair. */
syncId?: string | null;
terminalConfig?: Partial<TerminalConfig>;
2026-05-11 01:23:11 -05:00
useSocks5?: boolean;
socks5Host?: string;
socks5Port?: number;
+2
2026-07-26 18:47:27 -05:00
connectionOrigin?: "local" | "remote" | null;
2026-05-11 01:23:11 -05:00
socks5Username?: string;
socks5Password?: string;
socks5ProxyChain?: {
host: string;
port: number;
+5
2026-08-19 14:12:06 -05:00
type: 4 | 5 | "http" | "socks4" | "socks5";
2026-05-11 01:23:11 -05:00
username?: string;
password?: string;
}[];
+5
2026-08-19 14:12:06 -05:00
/** hostid is a legacy lowercase spelling still present in stored rows. */
jumpHosts?: { hostId: string; hostid?: string }[];
2026-05-11 01:23:11 -05:00
portKnockSequence?: {
port: number;
protocol: "tcp" | "udp";
delay: number;
}[];
enableTunnel: boolean;
serverTunnels: {
mode: "local" | "remote" | "dynamic";
bindHost?: string;
targetHost?: string;
sourcePort: number;
endpointHost: string;
endpointPort: number;
maxRetries: number;
retryInterval: number;
autoStart: boolean;
}[];
enableFileManager: boolean;
2026-06-21 15:55:41 -05:00
scpLegacy?: boolean;
2026-05-11 01:23:11 -05:00
defaultPath?: string;
enableDocker: boolean;
2026-06-29 13:28:26 -05:00
dockerConfig?: {
runtime?: "docker" | "podman";
} | null;
+2
2026-06-16 15:59:53 -05:00
enableProxmox: boolean;
enableTmuxMonitor: boolean;
+5
2026-08-19 14:12:06 -05:00
enableTerminalToolbar: boolean;
+2
2026-06-16 15:59:53 -05:00
proxmoxConfig?: {
+5
2026-08-19 14:12:06 -05:00
source?: {
source: "proxmox";
sourceHostId: number;
node: string;
vmid: number;
type: "qemu" | "lxc";
lastSeenAt?: string;
lastStatus?: string;
missingSince?: string | null;
};
+2
2026-06-16 15:59:53 -05:00
defaultCredentialId: number | null;
2026-06-21 15:55:41 -05:00
defaultAuthType?: string;
+2
2026-06-16 15:59:53 -05:00
windowsPatterns: string;
dockerPatterns: string;
preferredPrefixes: string;
+8
2026-07-19 12:29:52 -05:00
autoSyncEnabled?: boolean;
syncIntervalMinutes?: number;
markMissingGuests?: boolean;
lastSyncAt?: string;
lastSyncStatus?: "success" | "error";
lastSyncError?: string | null;
lastSyncResult?: {
created: number;
updated: number;
markedMissing: number;
skipped: number;
errors: string[];
};
+2
2026-06-16 15:59:53 -05:00
} | null;
+5
2026-08-19 14:12:06 -05:00
enableProxmoxStats: boolean;
proxmoxStatsConfig?: {
nodeName?: string | null;
pollInterval?: number;
enabledCards?: string[];
} | null;
2026-05-11 01:23:11 -05:00
+5
2026-08-19 14:12:06 -05:00
statsConfig?: StatsConfig;
2026-05-11 01:23:11 -05:00
quickActions: { name: string; snippetId: string }[];
enableSsh: boolean;
enableRdp: boolean;
enableVnc: boolean;
enableTelnet: boolean;
sshPort: number;
rdpPort: number;
vncPort: number;
telnetPort: number;
+2
2026-07-26 18:47:27 -05:00
rdpAuthType?: "direct" | "credential" | "none";
2026-06-21 15:55:41 -05:00
rdpCredentialId?: string;
2026-05-11 01:23:11 -05:00
rdpUser?: string;
rdpPassword?: string;
+2
2026-07-26 18:47:27 -05:00
hasRdpPassword?: boolean;
2026-05-11 01:23:11 -05:00
domain?: string;
security?: string;
ignoreCert?: boolean;
+2
2026-07-26 18:47:27 -05:00
vncAuthType?: "direct" | "credential";
2026-06-21 15:55:41 -05:00
vncCredentialId?: string;
2026-05-11 01:23:11 -05:00
vncPassword?: string;
+2
2026-07-26 18:47:27 -05:00
hasVncPassword?: boolean;
2026-05-11 01:23:11 -05:00
vncUser?: string;
+2
2026-07-26 18:47:27 -05:00
telnetAuthType?: "direct" | "credential";
telnetCredentialId?: string;
2026-05-11 01:23:11 -05:00
telnetUser?: string;
telnetPassword?: string;
+2
2026-07-26 18:47:27 -05:00
hasTelnetPassword?: boolean;
2026-05-11 01:23:11 -05:00
+5
2026-08-19 14:12:06 -05:00
guacamoleConfig?: GuacamoleConfig;
2026-05-28 22:29:20 -05:00
forceKeyboardInteractive?: boolean;
+8
2026-07-19 12:29:52 -05:00
isShared?: boolean;
+3
2026-08-06 14:41:39 -05:00
authOverrides?: HostAuthOverrides<string>;
+8
2026-07-19 12:29:52 -05:00
permissionLevel?: SharePermissionLevel;
sharedExpiresAt?: string;
ownerUsername?: string;
2026-05-11 01:23:11 -05:00
};
+8
2026-07-19 12:29:52 -05:00
export type SharePermissionLevel = "connect" | "view" | "edit" | "manage";
2026-05-11 01:23:11 -05:00
export type Credential = {
id: string;
name: string;
username: string;
type: "password" | "key";
value?: string;
2026-06-29 13:28:26 -05:00
password?: string;
2026-05-11 01:23:11 -05:00
publicKey?: string;
passphrase?: string;
description?: string;
folder?: string;
tags?: string[];
+5
2026-08-19 14:12:06 -05:00
pin?: boolean;
sortOrder?: number | null;
certPublicKey?: string;
2026-05-11 01:23:11 -05:00
};
2026-06-29 13:28:26 -05:00
// HashiCorp Vault SSH signer profile — shareable connection settings only
// (no secrets). Users authenticate to Vault via OIDC at connect time.
export type VaultProfile = {
id: string;
name: string;
description?: string;
folder?: string;
tags?: string[];
vaultAddr: string;
vaultNamespace?: string;
oidcMount?: string;
oidcRole?: string;
sshMount?: string;
sshRole: string;
validPrincipals?: string;
keyType?: string;
shared: boolean;
owned: boolean;
};
2026-05-11 01:23:11 -05:00
export type HostFolder = {
name: string;
children: (Host | HostFolder)[];
+2
2026-06-16 15:59:53 -05:00
path?: string;
color?: string;
icon?: string;
+2
2026-07-26 18:47:27 -05:00
credentialId?: number | null;
+5
2026-08-19 14:12:06 -05:00
sortOrder?: number | null;
2026-05-11 01:23:11 -05:00
};
export type TabType =
| "dashboard"
| "terminal"
+5
2026-08-19 14:12:06 -05:00
| "local-terminal"
2026-05-11 01:23:11 -05:00
| "rdp"
| "vnc"
| "telnet"
+2
2026-06-16 15:59:53 -05:00
| "host-metrics"
+5
2026-08-19 14:12:06 -05:00
| "proxmox-stats"
2026-05-11 01:23:11 -05:00
| "files"
| "host-manager"
| "user-profile"
| "admin-settings"
| "docker"
2026-05-28 22:29:20 -05:00
| "tunnel"
+2
2026-06-16 15:59:53 -05:00
| "network_graph"
2026-06-29 13:28:26 -05:00
| "tmux_monitor" // --- tmux-monitor ---
| "serial"
+5
2026-08-19 14:12:06 -05:00
| "homepage"
| "fleet-inventory"
// Rail panels that can also open full-width in the main area.
| "termix-id"
| "alerts"
| "session-logs"
| "snippets"
| "macros"
| "history"
| "ssh-tools"
| "automations"
| "ai"
| "split-screen";
2026-06-29 13:28:26 -05:00
export type SerialConfig = {
path: string;
baudRate: number;
dataBits: 5 | 6 | 7 | 8;
stopBits: 1 | 2;
parity: "none" | "even" | "odd";
};
2026-05-11 01:23:11 -05:00
export type Tab = {
id: string;
2026-05-28 22:05:25 -04:00
instanceId: string;
2026-05-11 01:23:11 -05:00
type: TabType;
label: string;
2026-06-21 15:55:41 -05:00
customLabel?: string;
2026-05-11 01:23:11 -05:00
host?: Host;
2026-05-28 22:05:25 -04:00
openedAt: number;
restoredSessionId?: string | null;
+2
2026-07-26 18:47:27 -05:00
/** Set when this tab joins someone else's live shared session instead of connecting/attaching its own. */
joinSharedSessionId?: string | null;
joinShareId?: string | null;
2026-06-21 15:55:41 -05:00
initialFilePath?: string;
+5
2026-08-19 14:12:06 -05:00
/** Directory to open a Files tab into, distinct from initialFilePath (a specific file to open in an editor window). */
initialPath?: string;
/** Which fleet a fleet-inventory tab is currently showing (singleton tab, re-targeted on reopen). */
fleetId?: number;
2026-06-29 13:28:26 -05:00
serialConfig?: SerialConfig;
+5
2026-08-19 14:12:06 -05:00
/** Present only on a split-screen container tab. Pane ids reference live child tabs. */
splitConfig?: SplitTabConfig;
/** Hides this session from the top-level tab bar while it belongs to a split tab. */
parentSplitTabId?: string;
2026-05-28 22:29:20 -05:00
terminalRef?: import("react").RefObject<{
2026-06-29 13:28:26 -05:00
disconnect?: () => void;
isConnected?: () => boolean;
2026-05-28 22:29:20 -05:00
sendInput?: (data: string) => void;
+5
2026-08-19 14:12:06 -05:00
subscribeOutput?: (listener: (data: string) => void) => () => void;
paste?: (text: string) => void;
2026-05-28 22:29:20 -05:00
reconnect?: () => void;
2026-06-04 15:16:53 -04:00
fit?: () => void;
notifyResize?: () => void;
+5
2026-08-19 14:12:06 -05:00
refresh?: () => void;
2026-06-21 15:55:41 -05:00
getApplicationCursorKeysMode?: () => boolean;
+2
2026-07-26 18:47:27 -05:00
openShareModal?: () => void;
canShare?: () => boolean;
2026-05-28 22:29:20 -05:00
} | null>;
2026-05-11 01:23:11 -05:00
};
export type DashboardCardId =
| "stats_bar"
| "counters_bar"
| "quick_actions"
| "host_status"
| "recent_activity"
2026-06-21 15:55:41 -05:00
| "network_graph"
2026-06-29 13:28:26 -05:00
| "service_links"
| "homepage_preview";
2026-05-11 01:23:11 -05:00
export type DashboardCardConfig = {
id: DashboardCardId;
label: string;
description: string;
defaultEnabled: boolean;
};
export type AdminSection =
| "general"
+2
2026-06-16 15:59:53 -05:00
| "sso"
2026-05-11 01:23:11 -05:00
| "users"
| "sessions"
| "roles"
2026-06-21 15:55:41 -05:00
| "host-defaults"
+5
2026-08-19 14:12:06 -05:00
| "image-storage"
2026-05-11 01:23:11 -05:00
| "database"
+2
2026-06-16 15:59:53 -05:00
| "api-keys"
2026-06-21 15:55:41 -05:00
| "audit-log"
+5
2026-08-19 14:12:06 -05:00
| "ssl"
| "touch-input";
2026-05-11 01:23:11 -05:00
export type ThemeId =
| "dark"
| "light"
| "system"
| "dracula"
| "catppuccin"
| "nord"
| "solarized"
| "tokyo-night"
| "one-dark"
| "gruvbox";
export type FontSizeId = "xs" | "sm" | "md" | "lg" | "xl";
+5
2026-08-19 14:12:06 -05:00
export type ToolsTab =
"ssh-tools" | "snippets" | "macros" | "history" | "split-screen";
2026-05-11 01:23:11 -05:00
export type SplitMode =
+5
2026-08-19 14:12:06 -05:00
| "none"
| "2-way"
| "2-way-horizontal"
| "3-way"
| "3-way-horizontal"
| "4-way"
| "5-way"
| "6-way";
export type SplitTabConfig = {
mode: Exclude<SplitMode, "none">;
paneTabIds: (string | null)[];
rowSizes: number[];
rowColSizes: number[][];
};
export type WorkspaceTabSnapshot = {
/** Stable key within the saved tab list, not the live Tab.id (which is regenerated on every open). */
slotId: string;
type: TabType;
/** Set for host-bound tab types, resolved by Host.syncId on apply. Never set for "serial". */
hostSyncId?: string | null;
/** Denormalized snapshot for display and graceful-skip messaging if the host is later deleted. */
hostNameSnapshot?: string | null;
label: string;
customLabel?: string;
initialFilePath?: string;
initialPath?: string;
fleetId?: number;
/** Only present when type === "serial". Fully self-contained, no host resolution needed. */
serialConfig?: SerialConfig;
};
/** One dock's arrangement. `view` is a RailView, or null when the dock is closed. */
export type WorkspaceDockState = {
view: string | null;
open: boolean;
width: number;
};
export type WorkspacePayload = {
version: 1;
tabs: WorkspaceTabSnapshot[];
activeSlotId: string | null;
splitMode: SplitMode;
/** Indexed identically to AppShell's paneTabIds (length 6), holding slotId instead of a live Tab.id. */
paneTabIds: (string | null)[];
rowSizes: number[];
rowColSizes: number[][];
/** Sidebar arrangement, so a workspace restores the whole layout and not just tabs. */
sidebar?: {
left: WorkspaceDockState;
right: WorkspaceDockState;
};
};
export type WorkspaceKind = "manual" | "last_session";
export type Workspace = {
id: number;
userId: string;
name: string;
color: string | null;
icon: string | null;
kind: WorkspaceKind;
isDefault: boolean;
payload: WorkspacePayload;
syncId: string | null;
createdAt: string;
updatedAt: string;
lastUsedAt: string | null;
tabCount: number;
};
2026-05-11 01:23:11 -05:00
export type Snippet = {
id: number;
name: string;
description?: string;
2026-05-28 22:29:20 -05:00
content: string;
folder: string | null;
2026-05-28 22:05:25 -04:00
order: number;
2026-06-21 15:55:41 -05:00
hostIds?: number[];
+5
2026-08-19 14:12:06 -05:00
isNote?: boolean;
2026-05-11 01:23:11 -05:00
};
export const FOLDER_ICONS = [
"folder",
"server",
"cloud",
"database",
"box",
"network",
"copy",
"settings",
"cpu",
"globe",
] as const;
export type FolderIconId = (typeof FOLDER_ICONS)[number];
export type SnippetFolder = {
id: number;
name: string;
color: string;
icon: FolderIconId;
open: boolean;
};