Notes and Expiry add
This commit is contained in:
@@ -208,6 +208,8 @@ async function initializeCompleteDatabase(): Promise<void> {
|
|||||||
force_keyboard_interactive TEXT,
|
force_keyboard_interactive TEXT,
|
||||||
stats_config TEXT,
|
stats_config TEXT,
|
||||||
terminal_config TEXT,
|
terminal_config TEXT,
|
||||||
|
notes TEXT,
|
||||||
|
expiration_date TEXT,
|
||||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_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
|
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", {
|
databaseLogger.success("Schema migration completed", {
|
||||||
operation: "schema_migration",
|
operation: "schema_migration",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ export const sshData = sqliteTable("ssh_data", {
|
|||||||
statsConfig: text("stats_config"),
|
statsConfig: text("stats_config"),
|
||||||
terminalConfig: text("terminal_config"),
|
terminalConfig: text("terminal_config"),
|
||||||
quickActions: text("quick_actions"),
|
quickActions: text("quick_actions"),
|
||||||
|
notes: text("notes"),
|
||||||
|
expirationDate: text("expiration_date"),
|
||||||
createdAt: text("created_at")
|
createdAt: text("created_at")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default(sql`CURRENT_TIMESTAMP`),
|
.default(sql`CURRENT_TIMESTAMP`),
|
||||||
|
|||||||
@@ -242,6 +242,8 @@ router.post(
|
|||||||
statsConfig,
|
statsConfig,
|
||||||
terminalConfig,
|
terminalConfig,
|
||||||
forceKeyboardInteractive,
|
forceKeyboardInteractive,
|
||||||
|
notes,
|
||||||
|
expirationDate,
|
||||||
} = hostData;
|
} = hostData;
|
||||||
if (
|
if (
|
||||||
!isNonEmptyString(userId) ||
|
!isNonEmptyString(userId) ||
|
||||||
@@ -284,6 +286,8 @@ router.post(
|
|||||||
statsConfig: statsConfig ? JSON.stringify(statsConfig) : null,
|
statsConfig: statsConfig ? JSON.stringify(statsConfig) : null,
|
||||||
terminalConfig: terminalConfig ? JSON.stringify(terminalConfig) : null,
|
terminalConfig: terminalConfig ? JSON.stringify(terminalConfig) : null,
|
||||||
forceKeyboardInteractive: forceKeyboardInteractive ? "true" : "false",
|
forceKeyboardInteractive: forceKeyboardInteractive ? "true" : "false",
|
||||||
|
notes: notes || null,
|
||||||
|
expirationDate: expirationDate || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (effectiveAuthType === "password") {
|
if (effectiveAuthType === "password") {
|
||||||
@@ -464,7 +468,13 @@ router.put(
|
|||||||
statsConfig,
|
statsConfig,
|
||||||
terminalConfig,
|
terminalConfig,
|
||||||
forceKeyboardInteractive,
|
forceKeyboardInteractive,
|
||||||
|
notes,
|
||||||
|
expirationDate,
|
||||||
} = hostData;
|
} = hostData;
|
||||||
|
|
||||||
|
// Temporary logging to debug notes and expirationDate
|
||||||
|
console.log("DEBUG - Update host data:", { notes, expirationDate });
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isNonEmptyString(userId) ||
|
!isNonEmptyString(userId) ||
|
||||||
!isNonEmptyString(ip) ||
|
!isNonEmptyString(ip) ||
|
||||||
@@ -507,6 +517,8 @@ router.put(
|
|||||||
statsConfig: statsConfig ? JSON.stringify(statsConfig) : null,
|
statsConfig: statsConfig ? JSON.stringify(statsConfig) : null,
|
||||||
terminalConfig: terminalConfig ? JSON.stringify(terminalConfig) : null,
|
terminalConfig: terminalConfig ? JSON.stringify(terminalConfig) : null,
|
||||||
forceKeyboardInteractive: forceKeyboardInteractive ? "true" : "false",
|
forceKeyboardInteractive: forceKeyboardInteractive ? "true" : "false",
|
||||||
|
notes: notes || null,
|
||||||
|
expirationDate: expirationDate || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (effectiveAuthType === "password") {
|
if (effectiveAuthType === "password") {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||||||
return (
|
return (
|
||||||
<textarea
|
<textarea
|
||||||
className={cn(
|
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,
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -681,6 +681,8 @@
|
|||||||
"folder": "Folder",
|
"folder": "Folder",
|
||||||
"tags": "Tags",
|
"tags": "Tags",
|
||||||
"pin": "Pin",
|
"pin": "Pin",
|
||||||
|
"notes": "Notes",
|
||||||
|
"expirationDate": "Expiration Date",
|
||||||
"passwordRequired": "Password is required when using password authentication",
|
"passwordRequired": "Password is required when using password authentication",
|
||||||
"sshKeyRequired": "SSH Private Key is required when using key authentication",
|
"sshKeyRequired": "SSH Private Key is required when using key authentication",
|
||||||
"keyTypeRequired": "Key Type is required when using key authentication",
|
"keyTypeRequired": "Key Type is required when using key authentication",
|
||||||
@@ -1605,6 +1607,8 @@
|
|||||||
"folder": "folder",
|
"folder": "folder",
|
||||||
"password": "password",
|
"password": "password",
|
||||||
"keyPassword": "key password",
|
"keyPassword": "key password",
|
||||||
|
"notes": "Add notes about this host...",
|
||||||
|
"expirationDate": "Select expiration date",
|
||||||
"pastePrivateKey": "Paste your private key here...",
|
"pastePrivateKey": "Paste your private key here...",
|
||||||
"pastePublicKey": "Paste your public key here...",
|
"pastePublicKey": "Paste your public key here...",
|
||||||
"credentialName": "My SSH Server",
|
"credentialName": "My SSH Server",
|
||||||
|
|||||||
@@ -649,6 +649,8 @@
|
|||||||
"folder": "Папка",
|
"folder": "Папка",
|
||||||
"tags": "Теги",
|
"tags": "Теги",
|
||||||
"pin": "Закрепить",
|
"pin": "Закрепить",
|
||||||
|
"notes": "Заметки",
|
||||||
|
"expirationDate": "Дата истечения",
|
||||||
"passwordRequired": "Пароль требуется при использовании аутентификации по паролю",
|
"passwordRequired": "Пароль требуется при использовании аутентификации по паролю",
|
||||||
"sshKeyRequired": "Приватный SSH-ключ требуется при использовании аутентификации по ключу",
|
"sshKeyRequired": "Приватный SSH-ключ требуется при использовании аутентификации по ключу",
|
||||||
"keyTypeRequired": "Тип ключа требуется при использовании аутентификации по ключу",
|
"keyTypeRequired": "Тип ключа требуется при использовании аутентификации по ключу",
|
||||||
@@ -1503,6 +1505,8 @@
|
|||||||
"folder": "папка",
|
"folder": "папка",
|
||||||
"password": "пароль",
|
"password": "пароль",
|
||||||
"keyPassword": "пароль ключа",
|
"keyPassword": "пароль ключа",
|
||||||
|
"notes": "Добавьте заметки об этом хосте...",
|
||||||
|
"expirationDate": "Выберите дату истечения",
|
||||||
"pastePrivateKey": "Вставьте ваш приватный ключ здесь...",
|
"pastePrivateKey": "Вставьте ваш приватный ключ здесь...",
|
||||||
"pastePublicKey": "Вставьте ваш публичный ключ здесь...",
|
"pastePublicKey": "Вставьте ваш публичный ключ здесь...",
|
||||||
"credentialName": "Мой SSH-сервер",
|
"credentialName": "Мой SSH-сервер",
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ export interface SSHHost {
|
|||||||
quickActions?: QuickAction[];
|
quickActions?: QuickAction[];
|
||||||
statsConfig?: string;
|
statsConfig?: string;
|
||||||
terminalConfig?: TerminalConfig;
|
terminalConfig?: TerminalConfig;
|
||||||
|
notes?: string;
|
||||||
|
expirationDate?: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
}
|
}
|
||||||
@@ -84,6 +86,8 @@ export interface SSHHostData {
|
|||||||
quickActions?: QuickActionData[];
|
quickActions?: QuickActionData[];
|
||||||
statsConfig?: string | Record<string, unknown>;
|
statsConfig?: string | Record<string, unknown>;
|
||||||
terminalConfig?: TerminalConfig;
|
terminalConfig?: TerminalConfig;
|
||||||
|
notes?: string;
|
||||||
|
expirationDate?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SSHFolder {
|
export interface SSHFolder {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
} from "@/components/ui/form.tsx";
|
} from "@/components/ui/form.tsx";
|
||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
import { PasswordInput } from "@/components/ui/password-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 { ScrollArea } from "@/components/ui/scroll-area.tsx";
|
||||||
import { Separator } from "@/components/ui/separator.tsx";
|
import { Separator } from "@/components/ui/separator.tsx";
|
||||||
import {
|
import {
|
||||||
@@ -565,6 +566,8 @@ export function HostManagerEditor({
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.default([]),
|
.default([]),
|
||||||
|
notes: z.string().optional(),
|
||||||
|
expirationDate: z.string().optional(),
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
if (data.authType === "none") {
|
if (data.authType === "none") {
|
||||||
@@ -657,6 +660,8 @@ export function HostManagerEditor({
|
|||||||
statsConfig: DEFAULT_STATS_CONFIG,
|
statsConfig: DEFAULT_STATS_CONFIG,
|
||||||
terminalConfig: DEFAULT_TERMINAL_CONFIG,
|
terminalConfig: DEFAULT_TERMINAL_CONFIG,
|
||||||
forceKeyboardInteractive: false,
|
forceKeyboardInteractive: false,
|
||||||
|
notes: "",
|
||||||
|
expirationDate: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -752,6 +757,8 @@ export function HostManagerEditor({
|
|||||||
: [],
|
: [],
|
||||||
},
|
},
|
||||||
forceKeyboardInteractive: Boolean(cleanedHost.forceKeyboardInteractive),
|
forceKeyboardInteractive: Boolean(cleanedHost.forceKeyboardInteractive),
|
||||||
|
notes: cleanedHost.notes || "",
|
||||||
|
expirationDate: cleanedHost.expirationDate || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (defaultAuthType === "password") {
|
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> = {
|
const submitData: Record<string, unknown> = {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
ip: data.ip,
|
ip: data.ip,
|
||||||
@@ -869,8 +879,12 @@ export function HostManagerEditor({
|
|||||||
statsConfig: data.statsConfig || DEFAULT_STATS_CONFIG,
|
statsConfig: data.statsConfig || DEFAULT_STATS_CONFIG,
|
||||||
terminalConfig: data.terminalConfig || DEFAULT_TERMINAL_CONFIG,
|
terminalConfig: data.terminalConfig || DEFAULT_TERMINAL_CONFIG,
|
||||||
forceKeyboardInteractive: Boolean(data.forceKeyboardInteractive),
|
forceKeyboardInteractive: Boolean(data.forceKeyboardInteractive),
|
||||||
|
notes: data.notes || "",
|
||||||
|
expirationDate: data.expirationDate || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("DEBUG - submitData:", { notes: submitData.notes, expirationDate: submitData.expirationDate });
|
||||||
|
|
||||||
submitData.credentialId = null;
|
submitData.credentialId = null;
|
||||||
submitData.password = null;
|
submitData.password = null;
|
||||||
submitData.key = null;
|
submitData.key = null;
|
||||||
@@ -1391,6 +1405,47 @@ export function HostManagerEditor({
|
|||||||
</FormItem>
|
</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>
|
</div>
|
||||||
<FormLabel className="mb-3 mt-3 font-bold">
|
<FormLabel className="mb-3 mt-3 font-bold">
|
||||||
{t("hosts.authentication")}
|
{t("hosts.authentication")}
|
||||||
|
|||||||
@@ -867,6 +867,8 @@ export async function createSSHHost(hostData: SSHHostData): Promise<SSHHost> {
|
|||||||
: null,
|
: null,
|
||||||
terminalConfig: hostData.terminalConfig || null,
|
terminalConfig: hostData.terminalConfig || null,
|
||||||
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
|
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
|
||||||
|
notes: hostData.notes || "",
|
||||||
|
expirationDate: hostData.expirationDate || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!submitData.enableTunnel) {
|
if (!submitData.enableTunnel) {
|
||||||
@@ -933,6 +935,8 @@ export async function updateSSHHost(
|
|||||||
: null,
|
: null,
|
||||||
terminalConfig: hostData.terminalConfig || null,
|
terminalConfig: hostData.terminalConfig || null,
|
||||||
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
|
forceKeyboardInteractive: Boolean(hostData.forceKeyboardInteractive),
|
||||||
|
notes: hostData.notes || "",
|
||||||
|
expirationDate: hostData.expirationDate || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!submitData.enableTunnel) {
|
if (!submitData.enableTunnel) {
|
||||||
|
|||||||
Reference in New Issue
Block a user