mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 22:55:24 +00:00
release-2.7.1 (#1296)
* Add Helm and GitOps deployment setup * fix: build better-sqlite3 from source in Docker (#1267) * fix: preserve runtime SSL settings (#1268) * fix: support forwarding from the memory SSH agent (#1269) * fix: support forwarding from the memory agent * style: format memory agent test * fix: prompt for encrypted SFTP key passphrases (#1270) * fix: prompt for SFTP key passphrases * style: format SSH key utility test * fix: include host context in automation notifications (#1271) * fix: include host context in automation notifications * style: format automation notification changes * fix: reserve sidebar height for host tags (#1272) * fix: keep host action rows stable at large font sizes (#1273) * fix: honor certificate setting during server probe (#1274) * fix: package standard Linux icon sizes (#1275) * fix: avoid duplicate Docker HTTPS listener (#1276) * Fix host status without metrics collection (#1277) * fix: allow eight-digit secure auth codes (#1263) Allow TOTP prompts to accept secure auth codes longer than six digits without blocking valid authentication attempts. Generated with Codebuff 🤖 Co-authored-by: Chetan <chetan.development@gmail.com> Co-authored-by: Codebuff <noreply@codebuff.com> * Harden Helm deployment defaults * Update Helm workflow action * Exclude Helm templates from Prettier * Fix browser RDP file drops (#1279) * Fix Proxmox guest credential usernames (#1280) * Add WSL local terminal option (#1281) * refactor: split the transfer engine into focused modules (#1282) * refactor: extract SFTP promisify helpers into sftp-promisify module * refactor: extract transfer timing and rate stats into transfer-stats module * refactor: extract transfer error classes and recovery checks into transfer-errors module * refactor: extract host/path utility helpers into transfer-host-utils module * refactor: extract SFTP directory tree helpers into transfer-sftp-dir module * refactor: extract segment copy job builder into transfer-segment-copy module * refactor: extract file scan and sample helpers into transfer-scan module * refactor: move throttled progress helper into transfer-stats module * style: format transfer modules * perf: optimize tmux monitor aggregation (#1283) * fix: reserve credential tag row height (#1284) * feat: edit AI provider model settings (#1285) * fix: clarify click-to-expand host setting (#1286) * fix: allow portable imports on remote databases (#1287) * fix: allow HTTPS to share the configured port (#1288) * fix: resolve synced jump hosts on the server (#1289) * fix: make terminal clipboard shortcuts layout independent (#1290) * fix: use compatible fetch dispatcher for Tailscale (#1291) * fix: add OIDC environment recovery override (#1292) * fix: coalesce rapid mobile terminal input (#1293) * fix: coalesce rapid mobile terminal input * fix: support clean xterm patch installs * fix: resolve synced remote desktop host IDs (#1295) * feat: make the SFTP file manager path bar editable (#1294) Co-authored-by: Maxime Bonillo <257463937+dropafterfree@users.noreply.github.com> Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com> * feat: add passkey sign in to the login screen * fix: remove rounded corners from the host list search bar * fix: stop image storage settings text wrapping to one word per line * fix: prevent malformed websocket messages from crashing the server * chore: increment version * fix: remove gaps between host rows in the sidebar list Keep sub-pixel row measurements and stop wiping the size cache on hover. * fix: Failed to connect through jump hosts (#1180) https://github.com/Termix-SSH/Support/issues/1180 * feat: Progress bar for file downloads in the file manager (#1158) https://github.com/Termix-SSH/Support/issues/1158 * feat: Allow setting Silent OIDC Login via ENV var (#1174) https://github.com/Termix-SSH/Support/issues/1174 * feat: `IdentityFile` to limit the number of attempts by agents (#1165) https://github.com/Termix-SSH/Support/issues/1165 * feat: Credentials clone (#1159) https://github.com/Termix-SSH/Support/issues/1159 * chore: update release notes * docs: move helm setup guide to the docs site * fix: type errors in FilteredAgent agent identity handling * fix: remove stale better-sqlite3 prebuilds so the source build is used * fix: actually build better-sqlite3 from source so arm64 docker images work * fix: credential edit pencil in host editor and add clone action to credential list * fix: clear editingHost so the credential pencil actually opens the editor * chore: run format and lint * fix: folder drag and drop upload failing in the file manager * chore: sync Crowdin translations for 2.7.1 --------- Co-authored-by: alex-ctms <alex-ctms@users.noreply.github.com> Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com> Co-authored-by: Chetan Kumar <74929596+ckloop@users.noreply.github.com> Co-authored-by: Chetan <chetan.development@gmail.com> Co-authored-by: Codebuff <noreply@codebuff.com> Co-authored-by: ZacharyZcR <payasonorahc@protonmail.com> Co-authored-by: dropafterfree <maxime.bonillo@gmail.com> Co-authored-by: Maxime Bonillo <257463937+dropafterfree@users.noreply.github.com>
This commit is contained in:
165 files changed
+6778
-2090
No files matched your search
@@ -16,6 +16,7 @@ import {
|
||||
getCredentials,
|
||||
getCredentialDetails,
|
||||
deleteCredential,
|
||||
duplicateCredential,
|
||||
updateCredential,
|
||||
deployCredentialToHost,
|
||||
renameCredentialFolder,
|
||||
@@ -111,6 +112,11 @@ export function HostManager({
|
||||
string | null
|
||||
>(null);
|
||||
const [editingCredFolderValue, setEditingCredFolderValue] = useState("");
|
||||
// Remembers the host being edited when its credential is opened for
|
||||
// editing, so "back" can return to that host instead of the list.
|
||||
const [credentialReturnHost, setCredentialReturnHost] = useState<
|
||||
Host | "new" | null
|
||||
>(null);
|
||||
const [termixIdLinkedIds, setTermixIdLinkedIds] = useState<Set<number>>(
|
||||
new Set(),
|
||||
);
|
||||
@@ -312,6 +318,21 @@ export function HostManager({
|
||||
}
|
||||
};
|
||||
|
||||
const handleCloneCredential = async (cred: Credential) => {
|
||||
try {
|
||||
await duplicateCredential(Number(cred.id), {
|
||||
name: t("credentials.clonedCredentialName", { name: cred.name }),
|
||||
});
|
||||
const res = await getCredentials();
|
||||
setCredentials(mapCredentials(res));
|
||||
window.dispatchEvent(new CustomEvent("termix:credentials-changed"));
|
||||
toast.success(t("credentials.clonedCredential", { name: cred.name }));
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : null;
|
||||
toast.error(msg || t("credentials.failedToCloneCredential"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteCredential = async (cred: Credential) => {
|
||||
await deleteCredential(Number(cred.id));
|
||||
setCredentials((prev) => prev.filter((c) => c.id !== cred.id));
|
||||
@@ -355,6 +376,18 @@ export function HostManager({
|
||||
}
|
||||
}
|
||||
|
||||
// Opens a host's credential for editing from within the host editor,
|
||||
// remembering the host so "back" returns to it instead of the list.
|
||||
async function handleEditCredentialFromHost(credentialId: string) {
|
||||
const cred = credentials.find((c) => String(c.id) === String(credentialId));
|
||||
if (!cred) return;
|
||||
setCredentialReturnHost(editingHost);
|
||||
await handleEditCredential(cred);
|
||||
// The editor view keys off editingHost, so it has to be cleared or the
|
||||
// host editor keeps rendering over the credential we just opened.
|
||||
setEditingHost(null);
|
||||
}
|
||||
|
||||
// Editor view: full-width with top tab bar instead of side nav
|
||||
const closeHostEditor = () => {
|
||||
setHostEditorDirty(false);
|
||||
@@ -423,6 +456,11 @@ export function HostManager({
|
||||
onClick={() => {
|
||||
if (isHost) {
|
||||
requestCloseHostEditor();
|
||||
} else if (credentialReturnHost) {
|
||||
setEditingHost(credentialReturnHost);
|
||||
setCredentialReturnHost(null);
|
||||
setEditingCredential(null);
|
||||
setActiveCredentialTab("general");
|
||||
} else {
|
||||
setEditingCredential(null);
|
||||
setActiveCredentialTab("general");
|
||||
@@ -434,7 +472,9 @@ export function HostManager({
|
||||
<span>
|
||||
{isHost
|
||||
? t("hosts.backToHosts")
|
||||
: t("credentials.backToCredentials")}
|
||||
: credentialReturnHost
|
||||
? t("hosts.backToHost")
|
||||
: t("credentials.backToCredentials")}
|
||||
</span>
|
||||
{isHost && editingHost !== "new" && (
|
||||
<span
|
||||
@@ -525,6 +565,7 @@ export function HostManager({
|
||||
onTabChange={setActiveHostTab}
|
||||
hosts={hosts}
|
||||
credentials={credentials}
|
||||
onEditCredential={handleEditCredentialFromHost}
|
||||
/>
|
||||
) : (
|
||||
<CredentialEditorView
|
||||
@@ -546,11 +587,21 @@ export function HostManager({
|
||||
.filter((f): f is string => !!f),
|
||||
),
|
||||
).sort()}
|
||||
saveAsNewHost={
|
||||
credentialReturnHost ? credentialReturnHost : undefined
|
||||
}
|
||||
onBack={() => {
|
||||
if (credentialReturnHost) {
|
||||
setEditingHost(credentialReturnHost);
|
||||
setCredentialReturnHost(null);
|
||||
setEditingCredential(null);
|
||||
setActiveCredentialTab("general");
|
||||
return;
|
||||
}
|
||||
setEditingCredential(null);
|
||||
setActiveCredentialTab("general");
|
||||
}}
|
||||
onSave={(saved) => {
|
||||
onSave={(saved, options) => {
|
||||
// The save endpoints are typed as an untyped record; these are
|
||||
// the fields this view reads back off the response.
|
||||
const result = saved as Partial<Credential> & {
|
||||
@@ -579,6 +630,27 @@ export function HostManager({
|
||||
}
|
||||
return [...prev, updated];
|
||||
});
|
||||
if (options?.assignToHost && credentialReturnHost) {
|
||||
const returnHost = credentialReturnHost;
|
||||
setCredentialReturnHost(null);
|
||||
if (returnHost !== "new") {
|
||||
setHosts((prev) =>
|
||||
prev.map((h) =>
|
||||
h.id === returnHost.id
|
||||
? { ...h, credentialId: String(result.id) }
|
||||
: h,
|
||||
),
|
||||
);
|
||||
}
|
||||
setEditingHost(
|
||||
returnHost === "new"
|
||||
? "new"
|
||||
: { ...returnHost, credentialId: String(result.id) },
|
||||
);
|
||||
setActiveHostTab("ssh");
|
||||
setEditingCredential(null);
|
||||
return;
|
||||
}
|
||||
setEditingCredential(null);
|
||||
setActiveCredentialTab("general");
|
||||
}}
|
||||
@@ -662,6 +734,7 @@ export function HostManager({
|
||||
setDeployDialog({ cred, hostId: "" })
|
||||
}
|
||||
onEditCredential={handleEditCredential}
|
||||
onCloneCredential={handleCloneCredential}
|
||||
onDeleteCredential={handleConfirmDeleteCredential}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user