Notes and Expiry add
This commit is contained in:
@@ -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",
|
||||
});
|
||||
|
||||
@@ -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`),
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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-сервер",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user