mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 06:35:24 +00:00
chore: lock the plugin boundary and remove 2.9.0 leftovers
This commit is contained in:
1 parent
6489b62ece
commit
2961297989
399 files changed
+3964
-5627
No files matched your search
@@ -2,7 +2,7 @@ export const AUTH_OVERRIDE_PROTOCOLS = ["ssh", "rdp", "vnc", "telnet"] as const;
|
||||
|
||||
export type AuthOverrideProtocol = (typeof AUTH_OVERRIDE_PROTOCOLS)[number];
|
||||
|
||||
export const SUPPORTED_AUTH_OVERRIDE_PROTOCOLS =
|
||||
const SUPPORTED_AUTH_OVERRIDE_PROTOCOLS =
|
||||
AUTH_OVERRIDE_PROTOCOLS satisfies readonly AuthOverrideProtocol[];
|
||||
|
||||
export const AUTH_PROTOCOL_METADATA = {
|
||||
|
||||
@@ -41,7 +41,3 @@ export type LogEntry = {
|
||||
message: string;
|
||||
details?: Record<string, unknown> | string;
|
||||
};
|
||||
|
||||
export interface ConnectionLogResponse {
|
||||
connectionLogs?: LogEntry[];
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
export const GRID_SIZE = 30;
|
||||
export const MIN_ZOOM = 0.4;
|
||||
export const MAX_ZOOM = 2.0;
|
||||
export const ZOOM_STEP = 0.1;
|
||||
|
||||
export type WidgetTypeId =
|
||||
| "service_link"
|
||||
| "folder"
|
||||
| "clock"
|
||||
| "notes"
|
||||
| "host_status"
|
||||
| "bookmark_list"
|
||||
| "weather"
|
||||
| "iframe_embed"
|
||||
| "rss_feed"
|
||||
| "metrics_chart"
|
||||
| "host_grid"
|
||||
| "ping_status"
|
||||
| "recent_activity"
|
||||
| "termix_uptime"
|
||||
| "system_overview"
|
||||
| "ssh_terminal"
|
||||
| "quick_connect"
|
||||
| "file_manager_widget"
|
||||
| "tunnel_widget"
|
||||
| "calendar"
|
||||
| "countdown"
|
||||
| "search_bar"
|
||||
| "text_banner"
|
||||
| "image_widget"
|
||||
| "markdown_notes"
|
||||
| "custom_api"
|
||||
| "service_grid"
|
||||
| "dashboard_links"
|
||||
| "search_links"
|
||||
| "link_tree"
|
||||
| "ssh_quick_connect"
|
||||
| (string & {});
|
||||
|
||||
export interface HomepageItemRow {
|
||||
id: number;
|
||||
userId: string;
|
||||
typeId: WidgetTypeId;
|
||||
title: string | null;
|
||||
config: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface HomepageLayoutEntry {
|
||||
itemId: number;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
zOrder?: number;
|
||||
}
|
||||
|
||||
export interface HomepageLayoutData {
|
||||
entries: HomepageLayoutEntry[];
|
||||
pan: { x: number; y: number };
|
||||
zoom: number;
|
||||
}
|
||||
|
||||
export interface HomepageLayoutRow {
|
||||
id: number;
|
||||
userId: string;
|
||||
layout: HomepageLayoutData;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CanvasWidget {
|
||||
id: number;
|
||||
typeId: WidgetTypeId;
|
||||
title: string | null;
|
||||
config: Record<string, unknown>;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
zOrder: number;
|
||||
}
|
||||
|
||||
// ---- Per-widget config shapes ----
|
||||
|
||||
export interface ServiceLinkConfig {
|
||||
url: string;
|
||||
description?: string;
|
||||
accentColor?: string;
|
||||
imageUrl?: string;
|
||||
showImage?: boolean;
|
||||
}
|
||||
|
||||
export interface FolderConfig {
|
||||
color?: string;
|
||||
isExpanded: boolean;
|
||||
}
|
||||
|
||||
export interface ClockConfig {
|
||||
timezone?: string;
|
||||
showSeconds: boolean;
|
||||
format: "12h" | "24h";
|
||||
}
|
||||
|
||||
export interface NotesConfig {
|
||||
content: string;
|
||||
backgroundColor?: string;
|
||||
}
|
||||
|
||||
export type HostMetricKey =
|
||||
"cpu" | "memory" | "disk" | "uptime" | "network" | "system" | "processes";
|
||||
|
||||
export interface HostStatusConfig {
|
||||
hostId: number;
|
||||
/** @deprecated use shownMetrics instead */
|
||||
showMetrics?: boolean;
|
||||
/** @deprecated use shownMetrics instead */
|
||||
showDisk?: boolean;
|
||||
shownMetrics: HostMetricKey[];
|
||||
showSparkline?: boolean;
|
||||
}
|
||||
|
||||
export interface BookmarkLink {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface BookmarkListConfig {
|
||||
links: BookmarkLink[];
|
||||
}
|
||||
|
||||
export interface WeatherConfig {
|
||||
location: string;
|
||||
unit: "C" | "F";
|
||||
showForecast: boolean;
|
||||
}
|
||||
|
||||
export interface IframeConfig {
|
||||
url: string;
|
||||
scrolling: boolean;
|
||||
}
|
||||
|
||||
export interface RssFeedConfig {
|
||||
feedUrl: string;
|
||||
maxItems: number;
|
||||
showDescription: boolean;
|
||||
}
|
||||
|
||||
// ---- New widget configs ----
|
||||
|
||||
export type MetricsChartMetric =
|
||||
"cpu" | "memory" | "disk" | "net_rx" | "net_tx";
|
||||
export type MetricsChartRange = "15m" | "1h" | "6h" | "24h";
|
||||
|
||||
export interface MetricsChartConfig {
|
||||
hostId: number;
|
||||
metric: MetricsChartMetric;
|
||||
range: MetricsChartRange;
|
||||
showCurrentValue: boolean;
|
||||
}
|
||||
|
||||
export interface HostGridConfig {
|
||||
hostIds: number[];
|
||||
showIp: boolean;
|
||||
columns: 2 | 3 | 4;
|
||||
}
|
||||
|
||||
export interface PingUrl {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface PingStatusConfig {
|
||||
urls: PingUrl[];
|
||||
refreshInterval: number;
|
||||
showLatency: boolean;
|
||||
}
|
||||
|
||||
/** Core activity types; plugin tabs record their own. */
|
||||
export type ActivityType = "file_manager" | "tunnel" | (string & {});
|
||||
|
||||
export interface RecentActivityConfig {
|
||||
maxItems: number;
|
||||
filterTypes: ActivityType[];
|
||||
showTimestamp: boolean;
|
||||
}
|
||||
|
||||
export interface DockerActivityConfig {
|
||||
maxItems: number;
|
||||
showHostName: boolean;
|
||||
}
|
||||
|
||||
export interface SshQuickConnectConfig {
|
||||
hostIds: number[];
|
||||
connectionType: QuickConnectType;
|
||||
showStatus: boolean;
|
||||
layout: "grid" | "list";
|
||||
}
|
||||
|
||||
export interface TermixUptimeConfig {
|
||||
showDetailed: boolean;
|
||||
}
|
||||
|
||||
export interface SystemOverviewConfig {
|
||||
showVersion: boolean;
|
||||
showDbHealth: boolean;
|
||||
showUptime: boolean;
|
||||
}
|
||||
|
||||
export interface FileManagerWidgetConfig {
|
||||
hostId: number;
|
||||
}
|
||||
|
||||
export interface SshTerminalConfig {
|
||||
hostId: number;
|
||||
autoConnect: boolean;
|
||||
}
|
||||
|
||||
/** Tab types a quick connect widget opens: core tools or plugin actions. */
|
||||
export type QuickConnectType = "files" | "tunnel" | (string & {});
|
||||
|
||||
export interface QuickConnectConfig {
|
||||
hostIds: number[];
|
||||
connectionTypes: QuickConnectType[];
|
||||
showStatus: boolean;
|
||||
layout: "grid" | "list";
|
||||
}
|
||||
|
||||
export interface CalendarConfig {
|
||||
timezone?: string;
|
||||
startOnMonday: boolean;
|
||||
}
|
||||
|
||||
export interface CountdownConfig {
|
||||
targetDate: string;
|
||||
label: string;
|
||||
showDays: boolean;
|
||||
showHours: boolean;
|
||||
}
|
||||
|
||||
export type SearchEngine = "google" | "duckduckgo" | "bing" | "custom";
|
||||
|
||||
export interface SearchBarConfig {
|
||||
engine: SearchEngine;
|
||||
customUrl?: string;
|
||||
placeholder?: string;
|
||||
openInNewTab: boolean;
|
||||
}
|
||||
|
||||
export type TextBannerFontSize = "sm" | "md" | "lg" | "xl";
|
||||
export type TextBannerAlign = "left" | "center" | "right";
|
||||
export type TextBannerWeight = "normal" | "semibold" | "bold";
|
||||
|
||||
export interface TextBannerConfig {
|
||||
text: string;
|
||||
fontSize: TextBannerFontSize;
|
||||
textAlign: TextBannerAlign;
|
||||
fontWeight: TextBannerWeight;
|
||||
backgroundColor?: string;
|
||||
}
|
||||
|
||||
export interface ImageWidgetConfig {
|
||||
imageUrl: string;
|
||||
fit: "contain" | "cover" | "fill";
|
||||
alt?: string;
|
||||
linkUrl?: string;
|
||||
}
|
||||
|
||||
export interface MarkdownNotesConfig {
|
||||
content: string;
|
||||
backgroundColor?: string;
|
||||
renderMarkdown: boolean;
|
||||
}
|
||||
|
||||
export type CustomApiDisplayMode = "value" | "json" | "table";
|
||||
|
||||
export interface CustomApiConfig {
|
||||
url: string;
|
||||
displayField?: string;
|
||||
label?: string;
|
||||
unit?: string;
|
||||
refreshInterval: number;
|
||||
displayMode: CustomApiDisplayMode;
|
||||
jsonPath?: string;
|
||||
}
|
||||
|
||||
export interface ServiceGridItem {
|
||||
label: string;
|
||||
url: string;
|
||||
imageUrl?: string;
|
||||
accentColor?: string;
|
||||
}
|
||||
|
||||
export interface ServiceGridConfig {
|
||||
services: ServiceGridItem[];
|
||||
columns: 2 | 3 | 4;
|
||||
showLabels: boolean;
|
||||
iconSize: "sm" | "md" | "lg";
|
||||
}
|
||||
|
||||
export interface DashboardLinksConfig {
|
||||
showIcons: boolean;
|
||||
columns: 1 | 2 | 3;
|
||||
maxItems?: number;
|
||||
}
|
||||
|
||||
export interface SearchLinkShortcut {
|
||||
label: string;
|
||||
queryTemplate: string;
|
||||
icon?: string;
|
||||
accentColor?: string;
|
||||
}
|
||||
|
||||
export interface SearchLinksConfig {
|
||||
shortcuts: SearchLinkShortcut[];
|
||||
}
|
||||
|
||||
export interface LinkTreeLink {
|
||||
label: string;
|
||||
url: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface LinkTreeSection {
|
||||
heading: string;
|
||||
links: LinkTreeLink[];
|
||||
}
|
||||
|
||||
export interface LinkTreeConfig {
|
||||
sections: LinkTreeSection[];
|
||||
compact: boolean;
|
||||
}
|
||||
|
||||
// ---- Widget registry types ----
|
||||
|
||||
export interface WidgetComponentProps<C = Record<string, unknown>> {
|
||||
widget: CanvasWidget;
|
||||
config: C;
|
||||
isReadOnly?: boolean;
|
||||
onConfigUpdate?: (config: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
export interface WidgetEditFormProps<C = Record<string, unknown>> {
|
||||
config: C;
|
||||
onChange: (config: C) => void;
|
||||
}
|
||||
|
||||
export interface WidgetTypeDefinition<C = Record<string, unknown>> {
|
||||
id: WidgetTypeId;
|
||||
name: string;
|
||||
description: string;
|
||||
category: "links" | "info" | "system" | "monitoring";
|
||||
icon: React.ReactNode;
|
||||
defaultConfig: C;
|
||||
defaultSize: { w: number; h: number };
|
||||
minSize: { w: number; h: number };
|
||||
component: React.ComponentType<WidgetComponentProps<C>>;
|
||||
editFormComponent?: React.ComponentType<WidgetEditFormProps<C>>;
|
||||
}
|
||||
|
||||
export interface DragState {
|
||||
widgetId: number;
|
||||
startMouseX: number;
|
||||
startMouseY: number;
|
||||
startWidgetX: number;
|
||||
startWidgetY: number;
|
||||
}
|
||||
|
||||
export interface ResizeState {
|
||||
widgetId: number;
|
||||
startMouseX: number;
|
||||
startMouseY: number;
|
||||
startW: number;
|
||||
startH: number;
|
||||
}
|
||||
|
||||
export interface ContextMenuAnchor {
|
||||
top: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
right: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface ContextMenuState {
|
||||
visible: boolean;
|
||||
screenX: number;
|
||||
screenY: number;
|
||||
canvasX: number;
|
||||
canvasY: number;
|
||||
anchorRect?: ContextMenuAnchor;
|
||||
}
|
||||
+10
-363
@@ -7,49 +7,12 @@ export type {
|
||||
HostAuthOverrideState,
|
||||
HostAuthOverrides,
|
||||
} from "./auth-protocols.js";
|
||||
|
||||
// ============================================================================
|
||||
// HOST TYPES (SSH, RDP, VNC, Telnet)
|
||||
// ============================================================================
|
||||
|
||||
export type ConnectionType = "ssh" | "rdp" | "vnc" | "telnet";
|
||||
/**
|
||||
* Core's own SSH auth types, plus whatever a plugin registers through
|
||||
* ctx.auth (the owning plugin decides the name).
|
||||
*/
|
||||
export type SSHAuthType =
|
||||
| "password"
|
||||
| "key"
|
||||
| "credential"
|
||||
| "none"
|
||||
| "opkssh"
|
||||
| "stepca"
|
||||
| "tailscale";
|
||||
|
||||
export type GuacamoleAuthType = "password" | "credential";
|
||||
|
||||
export interface ProxmoxStatsConfig {
|
||||
nodeName?: string | null;
|
||||
pollInterval?: number;
|
||||
enabledCards?: string[];
|
||||
}
|
||||
|
||||
export interface ProxmoxConfig {
|
||||
defaultCredentialId: number | null;
|
||||
defaultAuthType?: string;
|
||||
windowsPatterns: string;
|
||||
dockerPatterns: string;
|
||||
preferredPrefixes: string;
|
||||
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[];
|
||||
};
|
||||
}
|
||||
"password" | "key" | "credential" | "none" | "agent" | (string & {});
|
||||
|
||||
export type WebEndpointAccess = "direct" | "tunnel";
|
||||
export type WebEndpointRender = "external" | "embedded";
|
||||
@@ -93,15 +56,6 @@ export interface WebEndpoint {
|
||||
localPort?: number;
|
||||
}
|
||||
|
||||
export interface WebUiConfig {
|
||||
endpoints: WebEndpoint[];
|
||||
}
|
||||
|
||||
/** A host may declare at most this many web endpoints. */
|
||||
export const MAX_WEB_ENDPOINTS = 16;
|
||||
/** Endpoint labels are truncated to this length. */
|
||||
export const MAX_WEB_ENDPOINT_LABEL_LENGTH = 64;
|
||||
|
||||
export interface JumpHost {
|
||||
hostId: number;
|
||||
}
|
||||
@@ -120,16 +74,7 @@ export type Host = {
|
||||
folder: string;
|
||||
tags: string[];
|
||||
pin: boolean;
|
||||
authType:
|
||||
| "password"
|
||||
| "key"
|
||||
| "credential"
|
||||
| "none"
|
||||
| "opkssh"
|
||||
| "stepca"
|
||||
| "tailscale"
|
||||
| "agent"
|
||||
| "vault";
|
||||
authType: SSHAuthType;
|
||||
shareSshAuth?: boolean;
|
||||
password?: string;
|
||||
key?: string;
|
||||
@@ -254,16 +199,7 @@ export interface HostData {
|
||||
parentHostId?: number | string | null;
|
||||
tags?: string[];
|
||||
pin?: boolean;
|
||||
authType:
|
||||
| "password"
|
||||
| "key"
|
||||
| "credential"
|
||||
| "none"
|
||||
| "opkssh"
|
||||
| "stepca"
|
||||
| "tailscale"
|
||||
| "agent"
|
||||
| "vault";
|
||||
authType: SSHAuthType;
|
||||
shareSshAuth?: boolean;
|
||||
password?: string;
|
||||
key?: File | string | null;
|
||||
@@ -382,22 +318,6 @@ export interface CredentialBackend {
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface CredentialData {
|
||||
name: string;
|
||||
description?: string;
|
||||
folder?: string;
|
||||
tags: string[];
|
||||
authType: "password" | "key";
|
||||
username?: string;
|
||||
password?: string;
|
||||
key?: string;
|
||||
publicKey?: string;
|
||||
/** CA-signed certificate file content (e.g. id_ed25519-cert.pub) */
|
||||
certPublicKey?: string | null;
|
||||
keyPassword?: string;
|
||||
keyType?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TUNNEL TYPES
|
||||
// ============================================================================
|
||||
@@ -405,32 +325,6 @@ export interface CredentialData {
|
||||
export type TunnelScope = "s2s" | "c2s";
|
||||
export type TunnelMode = "local" | "remote" | "dynamic";
|
||||
|
||||
export interface TunnelConnection {
|
||||
scope?: TunnelScope;
|
||||
mode?: TunnelMode;
|
||||
tunnelType?: "local" | "remote";
|
||||
localAddress?: string;
|
||||
remoteAddress?: string;
|
||||
bindHost?: string;
|
||||
sourceHostId?: number;
|
||||
sourceHostSyncId?: string;
|
||||
sourceHostName?: string;
|
||||
sourcePort: number;
|
||||
endpointPort: number;
|
||||
endpointHost?: string;
|
||||
targetHost?: string;
|
||||
|
||||
endpointPassword?: string;
|
||||
endpointKey?: string;
|
||||
endpointKeyPassword?: string;
|
||||
endpointAuthType?: string;
|
||||
endpointKeyType?: string;
|
||||
|
||||
maxRetries: number;
|
||||
retryInterval: number;
|
||||
autoStart: boolean;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FILE MANAGER TYPES
|
||||
// ============================================================================
|
||||
@@ -447,61 +341,6 @@ export interface Tab {
|
||||
dirty?: boolean;
|
||||
}
|
||||
|
||||
export interface FileManagerFile {
|
||||
name: string;
|
||||
path: string;
|
||||
type?: "file" | "directory";
|
||||
isSSH?: boolean;
|
||||
sshSessionId?: string;
|
||||
}
|
||||
|
||||
export interface FileManagerShortcut {
|
||||
name: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface FileItem {
|
||||
name: string;
|
||||
path: string;
|
||||
isPinned?: boolean;
|
||||
type: "file" | "directory" | "link";
|
||||
sshSessionId?: string;
|
||||
size?: number;
|
||||
modified?: string;
|
||||
modifiedTimestamp?: number;
|
||||
permissions?: string;
|
||||
owner?: string;
|
||||
group?: string;
|
||||
linkTarget?: string;
|
||||
executable?: boolean;
|
||||
}
|
||||
|
||||
export interface ShortcutItem {
|
||||
name: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface SSHConnection {
|
||||
id: number;
|
||||
name: string;
|
||||
ip: string;
|
||||
port: number;
|
||||
username: string;
|
||||
isPinned?: boolean;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// HOST INFO TYPES
|
||||
// ============================================================================
|
||||
|
||||
export interface HostInfo {
|
||||
id: number;
|
||||
name?: string;
|
||||
ip: string;
|
||||
port: number;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ALERT TYPES
|
||||
// ============================================================================
|
||||
@@ -599,21 +438,8 @@ export interface TerminalConfig {
|
||||
export interface TabContextTab {
|
||||
id: number;
|
||||
instanceId?: string;
|
||||
type:
|
||||
| "home"
|
||||
| "terminal"
|
||||
| "ssh_manager"
|
||||
| "server_stats"
|
||||
| "admin"
|
||||
| "file_manager"
|
||||
| "user_profile"
|
||||
| "docker"
|
||||
| "tunnel"
|
||||
| "network_graph"
|
||||
| "tmux_monitor" // --- tmux-monitor ---
|
||||
| "rdp"
|
||||
| "vnc"
|
||||
| "telnet";
|
||||
/** A core tab type or one a plugin registered. */
|
||||
type: string;
|
||||
title: string;
|
||||
hostConfig?: SSHHost;
|
||||
terminalRef?: RefObject<TerminalRefHandle | null>;
|
||||
@@ -636,162 +462,6 @@ export interface TerminalRefHandle {
|
||||
|
||||
export type SplitLayout = "2h" | "2v" | "3l" | "3r" | "3t" | "4grid";
|
||||
|
||||
export interface SplitConfiguration {
|
||||
layout: SplitLayout;
|
||||
positions: Map<number, number>;
|
||||
}
|
||||
|
||||
export interface SplitLayoutOption {
|
||||
id: SplitLayout;
|
||||
name: string;
|
||||
description: string;
|
||||
cellCount: number;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CONNECTION STATES
|
||||
// ============================================================================
|
||||
|
||||
export const CONNECTION_STATES = {
|
||||
DISCONNECTED: "disconnected",
|
||||
CONNECTING: "connecting",
|
||||
CONNECTED: "connected",
|
||||
VERIFYING: "verifying",
|
||||
FAILED: "failed",
|
||||
UNSTABLE: "unstable",
|
||||
RETRYING: "retrying",
|
||||
WAITING: "waiting",
|
||||
DISCONNECTING: "disconnecting",
|
||||
} as const;
|
||||
|
||||
export type ConnectionState =
|
||||
(typeof CONNECTION_STATES)[keyof typeof CONNECTION_STATES];
|
||||
|
||||
export type ErrorType =
|
||||
| "CONNECTION_FAILED"
|
||||
| "AUTHENTICATION_FAILED"
|
||||
| "TIMEOUT"
|
||||
| "NETWORK_ERROR"
|
||||
| "UNKNOWN";
|
||||
|
||||
// ============================================================================
|
||||
// AUTHENTICATION TYPES
|
||||
// ============================================================================
|
||||
|
||||
export type AuthType =
|
||||
| "password"
|
||||
| "key"
|
||||
| "credential"
|
||||
| "none"
|
||||
| "opkssh"
|
||||
| "stepca"
|
||||
| "tailscale";
|
||||
|
||||
export type KeyType = "rsa" | "ecdsa" | "ed25519";
|
||||
|
||||
// ============================================================================
|
||||
// API RESPONSE TYPES
|
||||
// ============================================================================
|
||||
|
||||
export interface ApiResponse<T = unknown> {
|
||||
data?: T;
|
||||
error?: string;
|
||||
message?: string;
|
||||
status?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// COMPONENT PROP TYPES
|
||||
// ============================================================================
|
||||
|
||||
export interface CredentialsManagerProps {
|
||||
onEditCredential?: (credential: Credential) => void;
|
||||
onAddCredential?: () => void;
|
||||
}
|
||||
|
||||
export interface CredentialEditorProps {
|
||||
editingCredential?: Credential | null;
|
||||
onFormSubmit?: () => void;
|
||||
onBack?: () => void;
|
||||
}
|
||||
|
||||
export interface CredentialViewerProps {
|
||||
credential: Credential;
|
||||
onClose: () => void;
|
||||
onEdit: () => void;
|
||||
}
|
||||
|
||||
export interface CredentialSelectorProps {
|
||||
value?: number | null;
|
||||
onValueChange: (value: number | null) => void;
|
||||
}
|
||||
|
||||
export interface HostManagerProps {
|
||||
onSelectView?: (view: string) => void;
|
||||
isTopbarOpen?: boolean;
|
||||
initialTab?: string;
|
||||
hostConfig?: SSHHost;
|
||||
_updateTimestamp?: number;
|
||||
rightSidebarOpen?: boolean;
|
||||
rightSidebarWidth?: number;
|
||||
currentTabId?: number;
|
||||
updateTab?: (tabId: number, updates: Partial<Omit<Tab, "id">>) => void;
|
||||
}
|
||||
|
||||
export interface SSHManagerHostEditorProps {
|
||||
editingHost?: SSHHost | null;
|
||||
onFormSubmit?: () => void;
|
||||
}
|
||||
|
||||
export interface SSHManagerHostViewerProps {
|
||||
onEditHost?: (host: SSHHost) => void;
|
||||
onAddHost?: () => void;
|
||||
}
|
||||
|
||||
export interface HostProps {
|
||||
host: SSHHost;
|
||||
onHostConnect?: () => void;
|
||||
}
|
||||
|
||||
export interface FileManagerProps {
|
||||
onSelectView?: (view: string) => void;
|
||||
embedded?: boolean;
|
||||
initialHost?: SSHHost | null;
|
||||
}
|
||||
|
||||
export interface AlertCardProps {
|
||||
alert: TermixAlert;
|
||||
onDismiss: (alertId: string) => void;
|
||||
}
|
||||
|
||||
export interface AlertManagerProps {
|
||||
alerts: TermixAlert[];
|
||||
onDismiss: (alertId: string) => void;
|
||||
loggedIn: boolean;
|
||||
}
|
||||
|
||||
export interface FolderStats {
|
||||
totalHosts: number;
|
||||
hostsByType: Array<{
|
||||
type: string;
|
||||
count: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
// Snippet, SnippetFolder types live in ui-types.ts (the shape actually used
|
||||
// by SnippetsPanel.tsx); this file's older definitions were unused and removed.
|
||||
|
||||
// ============================================================================
|
||||
// UTILITY TYPES
|
||||
// ============================================================================
|
||||
|
||||
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
||||
|
||||
export type RequiredFields<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
||||
|
||||
export type PartialExcept<T, K extends keyof T> = Partial<T> & Pick<T, K>;
|
||||
|
||||
// ============================================================================
|
||||
// EXPRESS REQUEST TYPES
|
||||
// ============================================================================
|
||||
@@ -856,7 +526,7 @@ export interface CacheEntry<T = unknown> {
|
||||
export interface ExportSummary {
|
||||
sshHostsImported: number;
|
||||
sshCredentialsImported: number;
|
||||
fileManagerItemsImported: number;
|
||||
pluginItemsImported: number;
|
||||
dismissedAlertsImported: number;
|
||||
credentialUsageImported: number;
|
||||
settingsImported: number;
|
||||
@@ -864,29 +534,6 @@ export interface ExportSummary {
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
export interface ImportResult {
|
||||
success: boolean;
|
||||
summary: ExportSummary;
|
||||
}
|
||||
|
||||
export interface ExportRequestBody {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface ImportRequestBody {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface ExportPreviewBody {
|
||||
scope?: string;
|
||||
includeCredentials?: boolean;
|
||||
}
|
||||
|
||||
export interface RestoreRequestBody {
|
||||
backupPath: string;
|
||||
targetPath?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// DOCKER TYPES
|
||||
// ============================================================================
|
||||
@@ -1,124 +0,0 @@
|
||||
export interface ProxmoxGuest {
|
||||
name: string;
|
||||
vmid: number;
|
||||
type: "qemu" | "lxc";
|
||||
node: string;
|
||||
status: string;
|
||||
ip: string | null;
|
||||
connectionType: "ssh" | "rdp";
|
||||
enableDocker: boolean;
|
||||
}
|
||||
|
||||
export interface ProxmoxDiscoverResult {
|
||||
guests: ProxmoxGuest[];
|
||||
credentialId: number | null;
|
||||
defaultCredentialId: number | null;
|
||||
jumpHosts?: unknown[] | null;
|
||||
}
|
||||
|
||||
export interface ProxmoxSyncResult {
|
||||
created: number;
|
||||
updated: number;
|
||||
markedMissing: number;
|
||||
skipped: number;
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
// Frontend-side mirror of the backend Proxmox Stats collectors' return shapes
|
||||
// (src/backend/hosts/metrics/proxmox/*). Kept in sync by hand, same convention
|
||||
// as ServerMetrics in main-axios.ts mirroring collectMetrics.
|
||||
|
||||
export interface ProxmoxNodeStats {
|
||||
cpu: {
|
||||
percent: number | null;
|
||||
cores: number | null;
|
||||
load: [number, number, number] | null;
|
||||
};
|
||||
memory: {
|
||||
percent: number | null;
|
||||
usedGiB: number | null;
|
||||
totalGiB: number | null;
|
||||
};
|
||||
disk: {
|
||||
percent: number | null;
|
||||
usedGiB: number | null;
|
||||
totalGiB: number | null;
|
||||
};
|
||||
uptime: {
|
||||
seconds: number | null;
|
||||
formatted: string | null;
|
||||
};
|
||||
system: {
|
||||
hostname: string | null;
|
||||
kernel: string | null;
|
||||
pveVersion: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProxmoxNodeNetwork {
|
||||
interfaces: Array<{
|
||||
name: string;
|
||||
ip: string | null;
|
||||
state: string | null;
|
||||
rxBytes: string | null;
|
||||
txBytes: string | null;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface ProxmoxGuestSummary {
|
||||
vmid: number;
|
||||
name: string;
|
||||
type: "qemu" | "lxc";
|
||||
status: string;
|
||||
cpuPercent: number | null;
|
||||
memPercent: number | null;
|
||||
memUsedGiB: number | null;
|
||||
memTotalGiB: number | null;
|
||||
diskPercent: number | null;
|
||||
diskUsedGiB: number | null;
|
||||
diskTotalGiB: number | null;
|
||||
uptimeSeconds: number | null;
|
||||
}
|
||||
|
||||
export interface ProxmoxGuestsSummary {
|
||||
guests: ProxmoxGuestSummary[];
|
||||
counts: { running: number; stopped: number; total: number };
|
||||
}
|
||||
|
||||
export interface ProxmoxStoragePool {
|
||||
name: string;
|
||||
type: string;
|
||||
active: boolean;
|
||||
enabled: boolean;
|
||||
usedGiB: number | null;
|
||||
totalGiB: number | null;
|
||||
availGiB: number | null;
|
||||
percent: number | null;
|
||||
}
|
||||
|
||||
export interface ProxmoxStorage {
|
||||
pools: ProxmoxStoragePool[];
|
||||
}
|
||||
|
||||
export type ProxmoxClusterHealth =
|
||||
| { clustered: false }
|
||||
| {
|
||||
clustered: true;
|
||||
quorate: boolean;
|
||||
clusterName: string | null;
|
||||
nodes: Array<{
|
||||
name: string;
|
||||
online: boolean;
|
||||
local: boolean;
|
||||
ip: string | null;
|
||||
}>;
|
||||
};
|
||||
|
||||
export interface ProxmoxStatsSnapshot {
|
||||
node: ProxmoxNodeStats;
|
||||
network: ProxmoxNodeNetwork;
|
||||
guests: ProxmoxGuestsSummary;
|
||||
storage: ProxmoxStorage;
|
||||
cluster: ProxmoxClusterHealth;
|
||||
lastChecked: string;
|
||||
}
|
||||
+20
-62
@@ -32,17 +32,7 @@ export type UiAreaKey =
|
||||
| "dashboard"
|
||||
| "terminal"
|
||||
| "fileManager"
|
||||
| "hostEditor"
|
||||
| "homepage";
|
||||
|
||||
/**
|
||||
* The homepage area key, named rather than spelled inline in src/ui: it
|
||||
* happens to share its spelling with the homepage plugin's id, which
|
||||
* scripts/check-shell-plugin-ids.cjs treats as a plugin id wherever it sees
|
||||
* that literal under src/ui. This area predates plugins and is unrelated -
|
||||
* it is core's own widget-visibility override, not the plugin.
|
||||
*/
|
||||
export const HOMEPAGE_AREA_KEY: UiAreaKey = "homepage";
|
||||
| "hostEditor";
|
||||
|
||||
export type UiDensity = "comfortable" | "compact";
|
||||
export type UiTrayTrigger = "always" | "hover" | "click" | "actionsOnly";
|
||||
@@ -74,6 +64,11 @@ export interface UiCredentialListPreferences {
|
||||
|
||||
export interface UiRailPreferences {
|
||||
hiddenTabs: string[];
|
||||
/**
|
||||
* Also hide every plugin rail item that does not set simplePreset. Plugin
|
||||
* items are only known at runtime, so the preset cannot list them.
|
||||
*/
|
||||
hidePluginItems?: boolean;
|
||||
}
|
||||
|
||||
export interface UiDashboardPreferences {
|
||||
@@ -93,11 +88,6 @@ export interface UiHostEditorPreferences {
|
||||
mode: UiHostEditorMode;
|
||||
}
|
||||
|
||||
export interface UiHomepagePreferences {
|
||||
/** null means "never preset-driven" -- a preset must not touch the canvas. */
|
||||
enabledWidgets: string[] | null;
|
||||
}
|
||||
|
||||
export interface UiAreaPreferences {
|
||||
chrome: UiChromePreferences;
|
||||
hostList: UiHostListPreferences;
|
||||
@@ -107,7 +97,6 @@ export interface UiAreaPreferences {
|
||||
terminal: UiTerminalPreferences;
|
||||
fileManager: UiFileManagerPreferences;
|
||||
hostEditor: UiHostEditorPreferences;
|
||||
homepage: UiHomepagePreferences;
|
||||
}
|
||||
|
||||
/** A plugin's own area, keyed "plugin:<id>", holding what it declared in contributes.uiPresets. */
|
||||
@@ -134,34 +123,24 @@ export interface UiPreferences {
|
||||
const PRESET_VALUES: UiPreset[] = ["simple", "balanced", "advanced", "custom"];
|
||||
|
||||
/**
|
||||
* Rail views Simple keeps. Cutting all the way down to hosts+credentials makes
|
||||
* the app feel broken, so connections and snippets stay: snippets is the most
|
||||
* approachable power feature and connections is where troubleshooting starts.
|
||||
* Core rail views Simple keeps. Cutting all the way down to hosts+credentials
|
||||
* makes the app feel broken, so connections stays: it is where
|
||||
* troubleshooting starts. Plugin items opt in with simplePreset.
|
||||
*/
|
||||
const SIMPLE_RAIL_VISIBLE = ["hosts", "credentials", "connections", "snippets"];
|
||||
const SIMPLE_RAIL_VISIBLE = ["hosts", "credentials", "connections"];
|
||||
|
||||
/** Every hideable rail view, mirroring HideableRailView in sidebar/AppRail.tsx. */
|
||||
const ALL_HIDEABLE_RAIL_VIEWS = [
|
||||
/** Core's hideable rail views, mirroring RAIL_ITEMS in sidebar/rail-items.ts. */
|
||||
const CORE_HIDEABLE_RAIL_VIEWS = [
|
||||
"hosts",
|
||||
"credentials",
|
||||
"termix-id",
|
||||
"quick-connect",
|
||||
"serial",
|
||||
"ssh-tools",
|
||||
"snippets",
|
||||
"macros",
|
||||
"history",
|
||||
"split-screen",
|
||||
"connections",
|
||||
"session-logs",
|
||||
"fleets",
|
||||
"workspaces",
|
||||
"network_graph",
|
||||
"homepage",
|
||||
"ai",
|
||||
"quick-connect",
|
||||
"ssh-tools",
|
||||
"macros",
|
||||
"split-screen",
|
||||
];
|
||||
|
||||
const SIMPLE_HIDDEN_RAIL_TABS = ALL_HIDEABLE_RAIL_VIEWS.filter(
|
||||
const SIMPLE_HIDDEN_RAIL_TABS = CORE_HIDEABLE_RAIL_VIEWS.filter(
|
||||
(view) => !SIMPLE_RAIL_VISIBLE.includes(view),
|
||||
);
|
||||
|
||||
@@ -196,7 +175,7 @@ export const PRESETS: Record<Exclude<UiPreset, "custom">, UiAreaPreferences> = {
|
||||
rowActions: "essential",
|
||||
},
|
||||
credentialList: { density: "comfortable", showTags: false },
|
||||
rail: { hiddenTabs: SIMPLE_HIDDEN_RAIL_TABS },
|
||||
rail: { hiddenTabs: SIMPLE_HIDDEN_RAIL_TABS, hidePluginItems: true },
|
||||
dashboard: {
|
||||
enabledCards: [
|
||||
"stats_bar",
|
||||
@@ -208,7 +187,6 @@ export const PRESETS: Record<Exclude<UiPreset, "custom">, UiAreaPreferences> = {
|
||||
terminal: { toolbarDensity: "icon" },
|
||||
fileManager: { viewMode: "grid", showHiddenFiles: false },
|
||||
hostEditor: { mode: "simple" },
|
||||
homepage: { enabledWidgets: null },
|
||||
},
|
||||
balanced: {
|
||||
chrome: {
|
||||
@@ -232,7 +210,6 @@ export const PRESETS: Record<Exclude<UiPreset, "custom">, UiAreaPreferences> = {
|
||||
fileManager: { viewMode: "grid", showHiddenFiles: false },
|
||||
// 3 is defaultLayoutFromWidgets's own default, i.e. today's behavior.
|
||||
hostEditor: { mode: "full" },
|
||||
homepage: { enabledWidgets: null },
|
||||
},
|
||||
advanced: {
|
||||
chrome: {
|
||||
@@ -255,7 +232,6 @@ export const PRESETS: Record<Exclude<UiPreset, "custom">, UiAreaPreferences> = {
|
||||
// List packs more files and metadata per screen than the grid.
|
||||
fileManager: { viewMode: "list", showHiddenFiles: true },
|
||||
hostEditor: { mode: "full" },
|
||||
homepage: { enabledWidgets: null },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -263,8 +239,7 @@ type FieldSpec =
|
||||
| { kind: "enum"; values: readonly string[] }
|
||||
| { kind: "bool" }
|
||||
| { kind: "int"; min: number; max: number }
|
||||
| { kind: "stringArray" }
|
||||
| { kind: "nullableStringArray" };
|
||||
| { kind: "stringArray" };
|
||||
|
||||
/**
|
||||
* Field descriptors for every area knob. Unlike the flat sanitizers on the
|
||||
@@ -296,6 +271,7 @@ const AREA_SPECS: {
|
||||
},
|
||||
rail: {
|
||||
hiddenTabs: { kind: "stringArray" },
|
||||
hidePluginItems: { kind: "bool" },
|
||||
},
|
||||
dashboard: {
|
||||
enabledCards: { kind: "stringArray" },
|
||||
@@ -313,9 +289,6 @@ const AREA_SPECS: {
|
||||
hostEditor: {
|
||||
mode: { kind: "enum", values: ["simple", "full"] },
|
||||
},
|
||||
homepage: {
|
||||
enabledWidgets: { kind: "nullableStringArray" },
|
||||
},
|
||||
};
|
||||
|
||||
export const UI_AREA_KEYS = Object.keys(AREA_SPECS) as UiAreaKey[];
|
||||
@@ -340,11 +313,6 @@ function coerce(spec: FieldSpec, value: unknown): unknown | undefined {
|
||||
return Array.isArray(value)
|
||||
? value.filter((v): v is string => typeof v === "string")
|
||||
: undefined;
|
||||
case "nullableStringArray":
|
||||
if (value === null) return null;
|
||||
return Array.isArray(value)
|
||||
? value.filter((v): v is string => typeof v === "string")
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,13 +500,3 @@ export function resolvePluginArea(
|
||||
export function hasUiOverrides(preferences: UiPreferences): boolean {
|
||||
return Object.keys(preferences.overrides).length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* What the settings UI should show as the active preset. "custom" is derived
|
||||
* rather than stored, so clearing every override automatically restores the
|
||||
* user's chosen preset instead of stranding them on a label.
|
||||
*/
|
||||
export function effectivePresetLabel(preferences: UiPreferences): UiPreset {
|
||||
if (preferences.preset === "custom") return "custom";
|
||||
return hasUiOverrides(preferences) ? "custom" : preferences.preset;
|
||||
}
|
||||
+9
-46
@@ -1,4 +1,4 @@
|
||||
import type { TerminalConfig } from "./index.js";
|
||||
import type { SSHAuthType, TerminalConfig } from "./index.js";
|
||||
import type { HostAuthOverrides } from "./auth-protocols.js";
|
||||
|
||||
export type Host = {
|
||||
@@ -23,16 +23,7 @@ export type Host = {
|
||||
ram: number | null;
|
||||
lastAccess: string;
|
||||
tags?: string[];
|
||||
authType:
|
||||
| "password"
|
||||
| "key"
|
||||
| "credential"
|
||||
| "none"
|
||||
| "opkssh"
|
||||
| "stepca"
|
||||
| "tailscale"
|
||||
| "vault"
|
||||
| "agent";
|
||||
authType: SSHAuthType;
|
||||
shareSshAuth?: boolean;
|
||||
credentialId?: string;
|
||||
overrideCredentialUsername?: boolean;
|
||||
@@ -146,35 +137,15 @@ export type HostFolder = {
|
||||
sortOrder?: number | null;
|
||||
};
|
||||
|
||||
export type KnownTabType =
|
||||
/** Core's own tab types. Plugins register theirs at runtime. */
|
||||
type KnownTabType =
|
||||
| "dashboard"
|
||||
| "terminal"
|
||||
| "local-terminal"
|
||||
| "rdp"
|
||||
| "vnc"
|
||||
| "telnet"
|
||||
| "host-metrics"
|
||||
| "proxmox-stats"
|
||||
| "files"
|
||||
| "host-manager"
|
||||
| "user-profile"
|
||||
| "admin-settings"
|
||||
| "docker"
|
||||
| "tunnel"
|
||||
| "sftp"
|
||||
| "web-endpoint"
|
||||
| "network_graph"
|
||||
| "tmux_monitor" // --- tmux-monitor ---
|
||||
| "serial"
|
||||
| "homepage"
|
||||
| "fleet-inventory"
|
||||
// Rail panels that can also open full-width in the main area.
|
||||
| "session-logs"
|
||||
| "snippets"
|
||||
| "macros"
|
||||
| "history"
|
||||
| "ssh-tools"
|
||||
| "automations"
|
||||
| "split-screen";
|
||||
|
||||
/**
|
||||
@@ -273,8 +244,8 @@ export type UiFontId =
|
||||
| "source-code-pro"
|
||||
| "caskaydia-cove";
|
||||
|
||||
export type ToolsTab =
|
||||
"ssh-tools" | "snippets" | "macros" | "history" | "split-screen";
|
||||
/** A tools panel view: core's own, or a rail panel a plugin registered. */
|
||||
export type ToolsTab = "ssh-tools" | "macros" | "split-screen" | (string & {});
|
||||
export type SplitMode =
|
||||
| "none"
|
||||
| "2-way"
|
||||
@@ -311,7 +282,7 @@ export type WorkspaceTabSnapshot = {
|
||||
};
|
||||
|
||||
/** One dock's arrangement. `view` is a RailView, or null when the dock is closed. */
|
||||
export type WorkspaceDockState = {
|
||||
type WorkspaceDockState = {
|
||||
view: string | null;
|
||||
open: boolean;
|
||||
width: number;
|
||||
@@ -344,7 +315,7 @@ export type Snippet = {
|
||||
isNote?: boolean;
|
||||
};
|
||||
|
||||
export const FOLDER_ICONS = [
|
||||
const FOLDER_ICONS = [
|
||||
"folder",
|
||||
"server",
|
||||
"cloud",
|
||||
@@ -356,12 +327,4 @@ export const FOLDER_ICONS = [
|
||||
"cpu",
|
||||
"globe",
|
||||
] as const;
|
||||
export type FolderIconId = (typeof FOLDER_ICONS)[number];
|
||||
|
||||
export type SnippetFolder = {
|
||||
id: number;
|
||||
name: string;
|
||||
color: string;
|
||||
icon: FolderIconId;
|
||||
open: boolean;
|
||||
};
|
||||
type FolderIconId = (typeof FOLDER_ICONS)[number];
|
||||
Reference in new issue
Block a user