主机备注功能与脚本编辑体验优化 (#1158)

This commit is contained in:
pplulee
2026-05-31 15:39:26 +08:00
committed by GitHub
parent 4769668ff9
commit 4d7c56e537
19 changed files with 331 additions and 52 deletions

View File

@@ -254,11 +254,13 @@ export const sanitizeHost = (host: Host): Host => {
? 'auto'
: undefined;
const migrated = migrateDeprecatedFontOverride(host);
const cleanNotes = host.notes?.trim() || undefined;
return {
...migrated,
hostname: cleanHostname,
distro: cleanDistro,
distroMode: cleanDistroMode,
manualDistro: cleanManualDistro || undefined,
notes: cleanNotes,
};
};

View File

@@ -176,6 +176,8 @@ export interface Host {
localShellArgs?: string[];
localShellName?: string;
localShellIcon?: string;
/** User-authored Markdown notes (project, hardware, region, etc.) */
notes?: string;
}
export type KeyType = 'RSA' | 'ECDSA' | 'ED25519';

View File

@@ -157,8 +157,10 @@ const createHost = (input: {
protocol?: Exclude<HostProtocol, "mosh">;
group?: string;
tags?: string[];
notes?: string;
}): Host => {
const now = Date.now();
const notes = input.notes?.trim() || undefined;
return {
id: crypto.randomUUID(),
label: input.label?.trim() || input.hostname,
@@ -171,6 +173,7 @@ const createHost = (input: {
os: "linux",
protocol: input.protocol ?? "ssh",
createdAt: now,
...(notes ? { notes } : {}),
};
};
@@ -259,6 +262,7 @@ const importFromCsv = (text: string): VaultImportResult => {
const groupsIdx = findHeaderIndex(header, ["groups", "group", "folder", "path"]);
const labelIdx = findHeaderIndex(header, ["label", "name"]);
const tagsIdx = findHeaderIndex(header, ["tags", "tag"]);
const notesIdx = findHeaderIndex(header, ["notes", "note", "remark", "description", "memo"]);
const hostnameIdx = findHeaderIndex(header, ["hostname", "host", "server"]);
const protocolIdx = findHeaderIndex(header, ["protocol", "proto", "scheme"]);
const portIdx = findHeaderIndex(header, ["port"]);
@@ -303,6 +307,8 @@ const importFromCsv = (text: string): VaultImportResult => {
const group = groupsIdx >= 0 ? normalizeGroupPath(row[groupsIdx]) : undefined;
const label = labelIdx >= 0 ? row[labelIdx] : undefined;
const tags = tagsIdx >= 0 ? splitTags(row[tagsIdx]) : [];
const notesRaw = notesIdx >= 0 ? row[notesIdx] : undefined;
const notes = notesRaw?.trim() || undefined;
const protocol =
normalizeProtocol(protocolIdx >= 0 ? row[protocolIdx] : undefined) ??
target.protocol ??
@@ -321,6 +327,7 @@ const importFromCsv = (text: string): VaultImportResult => {
protocol,
group,
tags,
notes,
}),
);
}

View File

@@ -8,12 +8,12 @@ export const getVaultCsvTemplate = (
opts: VaultCsvTemplateOptions = {},
): string => {
const includeExampleRows = opts.includeExampleRows !== false;
const header = ["Groups", "Label", "Tags", "Hostname/IP", "Protocol", "Port", "Username", "Password"];
const header = ["Groups", "Label", "Tags", "Notes", "Hostname/IP", "Protocol", "Port", "Username", "Password"];
const rows: string[][] = [header];
if (includeExampleRows) {
rows.push(["Project/Dev", "Web Server (dev)", "dev,web", "192.168.1.10", "ssh", "22", "root", ""]);
rows.push(["Project/Prod", "Web Server (prod)", "prod,web", "server-a.example.com", "ssh", "22", "ubuntu", ""]);
rows.push(["Database", "DB", "db,mysql", "db.example.com", "ssh", "4567", "admin", ""]);
rows.push(["Project/Dev", "Web Server (dev)", "dev,web", "Dev web tier", "192.168.1.10", "ssh", "22", "root", ""]);
rows.push(["Project/Prod", "Web Server (prod)", "prod,web", "Production", "server-a.example.com", "ssh", "22", "ubuntu", ""]);
rows.push(["Database", "DB", "db,mysql", "MySQL primary", "db.example.com", "ssh", "4567", "admin", ""]);
}
const escapeCsv = (value: string) => {
@@ -26,7 +26,7 @@ export const getVaultCsvTemplate = (
};
const exportHostsToCsv = (hosts: Host[]): string => {
const header = ["Groups", "Label", "Tags", "Hostname/IP", "Protocol", "Port", "Username", "Password"];
const header = ["Groups", "Label", "Tags", "Notes", "Hostname/IP", "Protocol", "Port", "Username", "Password"];
const rows: string[][] = [header];
const escapeCsv = (value: string, skipFormulaGuard = false) => {
@@ -71,6 +71,7 @@ const exportHostsToCsv = (hosts: Host[]): string => {
host.group ?? "",
host.label ?? "",
(host.tags ?? []).join(","),
host.notes ?? "",
formatHostname(host.hostname),
host.protocol ?? "ssh",
String(effectivePort),