Notes and Expiry add

This commit is contained in:
Denis
2025-12-18 16:06:14 +07:00
parent f0647dc7c1
commit a06f5ad1af
9 changed files with 92 additions and 1 deletions

View File

@@ -208,6 +208,8 @@ async function initializeCompleteDatabase(): Promise<void> {
force_keyboard_interactive TEXT,
stats_config TEXT,
terminal_config TEXT,
notes TEXT,
expiration_date TEXT,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
@@ -551,6 +553,10 @@ const migrateSchema = () => {
}
}
// Add new columns for notes and expiration_date
addColumnIfNotExists("ssh_data", "notes", "TEXT");
addColumnIfNotExists("ssh_data", "expiration_date", "TEXT");
databaseLogger.success("Schema migration completed", {
operation: "schema_migration",
});

View File

@@ -90,6 +90,8 @@ export const sshData = sqliteTable("ssh_data", {
statsConfig: text("stats_config"),
terminalConfig: text("terminal_config"),
quickActions: text("quick_actions"),
notes: text("notes"),
expirationDate: text("expiration_date"),
createdAt: text("created_at")
.notNull()
.default(sql`CURRENT_TIMESTAMP`),

View File

@@ -242,6 +242,8 @@ router.post(
statsConfig,
terminalConfig,
forceKeyboardInteractive,
notes,
expirationDate,
} = hostData;
if (
!isNonEmptyString(userId) ||
@@ -284,6 +286,8 @@ router.post(
statsConfig: statsConfig ? JSON.stringify(statsConfig) : null,
terminalConfig: terminalConfig ? JSON.stringify(terminalConfig) : null,
forceKeyboardInteractive: forceKeyboardInteractive ? "true" : "false",
notes: notes || null,
expirationDate: expirationDate || null,
};
if (effectiveAuthType === "password") {
@@ -464,7 +468,13 @@ router.put(
statsConfig,
terminalConfig,
forceKeyboardInteractive,
notes,
expirationDate,
} = hostData;
// Temporary logging to debug notes and expirationDate
console.log("DEBUG - Update host data:", { notes, expirationDate });
if (
!isNonEmptyString(userId) ||
!isNonEmptyString(ip) ||
@@ -507,6 +517,8 @@ router.put(
statsConfig: statsConfig ? JSON.stringify(statsConfig) : null,
terminalConfig: terminalConfig ? JSON.stringify(terminalConfig) : null,
forceKeyboardInteractive: forceKeyboardInteractive ? "true" : "false",
notes: notes || null,
expirationDate: expirationDate || null,
};
if (effectiveAuthType === "password") {

View File

@@ -9,7 +9,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"flex min-h-[80px] w-full rounded-md border border-input bg-transparent dark:bg-input/30 px-3 py-2 text-sm shadow-xs transition-[color,box-shadow] duration-200 outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none",
className,
)}
ref={ref}

View File

@@ -681,6 +681,8 @@
"folder": "Folder",
"tags": "Tags",
"pin": "Pin",
"notes": "Notes",
"expirationDate": "Expiration Date",
"passwordRequired": "Password is required when using password authentication",
"sshKeyRequired": "SSH Private Key is required when using key authentication",
"keyTypeRequired": "Key Type is required when using key authentication",
@@ -1605,6 +1607,8 @@
"folder": "folder",
"password": "password",
"keyPassword": "key password",
"notes": "Add notes about this host...",
"expirationDate": "Select expiration date",
"pastePrivateKey": "Paste your private key here...",
"pastePublicKey": "Paste your public key here...",
"credentialName": "My SSH Server",

View File

@@ -649,6 +649,8 @@
"folder": "Папка",
"tags": "Теги",
"pin": "Закрепить",
"notes": "Заметки",
"expirationDate": "Дата истечения",
"passwordRequired": "Пароль требуется при использовании аутентификации по паролю",
"sshKeyRequired": "Приватный SSH-ключ требуется при использовании аутентификации по ключу",
"keyTypeRequired": "Тип ключа требуется при использовании аутентификации по ключу",
@@ -1503,6 +1505,8 @@
"folder": "папка",
"password": "пароль",
"keyPassword": "пароль ключа",
"notes": "Добавьте заметки об этом хосте...",
"expirationDate": "Выберите дату истечения",
"pastePrivateKey": "Вставьте ваш приватный ключ здесь...",
"pastePublicKey": "Вставьте ваш публичный ключ здесь...",
"credentialName": "Мой SSH-сервер",

View File

@@ -46,6 +46,8 @@ export interface SSHHost {
quickActions?: QuickAction[];
statsConfig?: string;
terminalConfig?: TerminalConfig;
notes?: string;
expirationDate?: string;
createdAt: string;
updatedAt: string;
}
@@ -84,6 +86,8 @@ export interface SSHHostData {
quickActions?: QuickActionData[];
statsConfig?: string | Record<string, unknown>;
terminalConfig?: TerminalConfig;
notes?: string;
expirationDate?: string;
}
export interface SSHFolder {

View File

@@ -14,6 +14,7 @@ import {
} from "@/components/ui/form.tsx";
import { Input } from "@/components/ui/input.tsx";
import { PasswordInput } from "@/components/ui/password-input.tsx";
import { Textarea } from "@/components/ui/textarea.tsx";
import { ScrollArea } from "@/components/ui/scroll-area.tsx";
import { Separator } from "@/components/ui/separator.tsx";
import {
@@ -565,6 +566,8 @@ export function HostManagerEditor({
}),
)
.default([]),
notes: z.string().optional(),
expirationDate: z.string().optional(),
})
.superRefine((data, ctx) => {
if (data.authType === "none") {
@@ -657,6 +660,8 @@ export function HostManagerEditor({
statsConfig: DEFAULT_STATS_CONFIG,
terminalConfig: DEFAULT_TERMINAL_CONFIG,
forceKeyboardInteractive: false,
notes: "",
expirationDate: "",
},
});
@@ -752,6 +757,8 @@ export function HostManagerEditor({
: [],
},
forceKeyboardInteractive: Boolean(cleanedHost.forceKeyboardInteractive),
notes: cleanedHost.notes || "",
expirationDate: cleanedHost.expirationDate || "",
};
if (defaultAuthType === "password") {
@@ -849,6 +856,9 @@ export function HostManagerEditor({
}
}
// Debug logging
console.log("DEBUG - Form data:", { notes: data.notes, expirationDate: data.expirationDate });
const submitData: Record<string, unknown> = {
name: data.name,
ip: data.ip,
@@ -869,8 +879,12 @@ export function HostManagerEditor({
statsConfig: data.statsConfig || DEFAULT_STATS_CONFIG,
terminalConfig: data.terminalConfig || DEFAULT_TERMINAL_CONFIG,
forceKeyboardInteractive: Boolean(data.forceKeyboardInteractive),
notes: data.notes || "",
expirationDate: data.expirationDate || "",
};
console.log("DEBUG - submitData:", { notes: submitData.notes, expirationDate: submitData.expirationDate });
submitData.credentialId = null;
submitData.password = null;
submitData.key = null;
@@ -1391,6 +1405,47 @@ export function HostManagerEditor({
</FormItem>
)}
/>
<FormField
control={form.control}
name="expirationDate"
render={({ field }) => (
<FormItem className="col-span-10">
<FormLabel>{t("hosts.expirationDate")}</FormLabel>
<FormControl>
<Input
type="date"
placeholder={t("placeholders.expirationDate")}
value={field.value || ""}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="notes"
render={({ field }) => (
<FormItem className="col-span-26">
<FormLabel>{t("hosts.notes")}</FormLabel>
<FormControl>
<Textarea
placeholder={t("placeholders.notes")}
className="resize-none"
rows={3}
value={field.value || ""}
onChange={field.onChange}
onBlur={field.onBlur}
name={field.name}
/>
</FormControl>
</FormItem>
)}
/>
</div>
<FormLabel className="mb-3 mt-3 font-bold">
{t("hosts.authentication")}

View File

@@ -867,6 +867,8 @@ export async function createSSHHost(hostData: SSHHostData): Promise<SSHHost> {
: null,
terminalConfig: hostData.terminalConfig || null,
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
notes: hostData.notes || "",
expirationDate: hostData.expirationDate || "",
};
if (!submitData.enableTunnel) {
@@ -933,6 +935,8 @@ export async function updateSSHHost(
: null,
terminalConfig: hostData.terminalConfig || null,
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
notes: hostData.notes || "",
expirationDate: hostData.expirationDate || "",
};
if (!submitData.enableTunnel) {