* Guacd, Docker-Compose, RDP (#475)

* fix select edit host but not update view (#438)

* fix: Checksum issue with chocolatey

* fix: Remove homebrew old stuff

* Add Korean translation (#439)

Co-authored-by: 송준우 <2484@coreit.co.kr>

* feat: Automate flatpak

* fix: Add imagemagik to electron builder to resolve build error

* fix: Build error with runtime repo flag

* fix: Flatpak runtime error and install freedesktop ver warning

* fix: Flatpak runtime error and install freedesktop ver warning

* feat: Re-add homebrew cask and move scripts to backend

* fix: No sandbox flag issue

* fix: Change name for electron macos cask output

* fix: Sandbox error with Linux

* fix: Remove comming soon for app stores in readme

* Adding Comment at the end of the public_key on the host on deploy (#440)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* -Add New Interface for Credential DB
-Add Credential Name as a comment into the server authorized_key file

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Sudo auto fill password (#441)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Feature Sudo password auto-fill;

* Fix locale json shema;

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Added Italian Language; (#445)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Added Italian Language;

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Auto collapse snippet folders (#448)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* feat: Add collapsable snippets (customizable in user profile)

* Translations (#447)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Added Italian Language;

* Fix translations;

Removed duplicate keys, synchronised other languages using English as the source, translated added keys, fixed inaccurate translations.

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Remove PTY-level keepalive (#449)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Remove PTY-level keepalive to prevent unwanted terminal output; use SSH-level keepalive instead

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* feat: add Guacamole support for RDP, VNC, and Telnet connections

- Implemented WebSocket support for Guacamole in Nginx configuration.
- Added REST API endpoints for generating connection tokens and checking guacd status.
- Created Guacamole server using guacamole-lite for handling connections.
- Developed frontend components for testing RDP/VNC connections and displaying the remote session.
- Updated package dependencies to include guacamole-common-js and guacamole-lite.
- Enhanced logging for Guacamole operations.

* feat: enhance Guacamole support with RDP and VNC connection settings and UI updates

* feat: Seperate server stats and tunnel management (improved both UI's) then started initial docker implementation

* fix: finalize adding docker to db

* fix: merge syntax errors

* feat: implement mouse coordinate adjustment based on scale factor in GuacamoleDisplay

* feat: add TypeScript definitions for guacamole-common-js module

* feat: enhance Mouse.State constructor to accept optional parameters and object destructuring

* feat: Add support for RDP and VNC connections in SSH host management

- Introduced connectionType field to differentiate between SSH, RDP, VNC, and Telnet in host data structures.
- Updated backend routes to handle RDP/VNC specific fields: domain, security, and ignoreCert.
- Enhanced the HostManagerEditor to include RDP/VNC specific settings and authentication options.
- Implemented token retrieval for RDP/VNC connections using Guacamole API.
- Updated UI components to reflect connection type changes and provide appropriate connection buttons.
- Removed the GuacamoleTestDialog component as its functionality is integrated into the HostManagerEditor.
- Adjusted the TopNavbar and Host components to accommodate new connection types and their respective actions.

* feat: Enhance Guacamole integration with extended configuration options

- Added detailed Guacamole configuration interface for RDP/VNC/Telnet connections, including display, audio, performance, and session settings.
- Implemented logging for token requests and received options for better debugging.
- Updated HostManagerEditor to support new Guacamole configuration fields with validation and default values.
- Integrated Guacamole configuration parsing in HostManagerViewer and Host components.
- Enhanced API requests to include extended Guacamole configuration parameters in the token request.
- Refactored code to convert camelCase configuration keys to kebab-case for compatibility with Guacamole API.

* feat: merge guacd into 2.0.0 and improve UI for host manager and made general bug fixes

---------

Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: junu <bigdwarf_@naver.com>
Co-authored-by: 송준우 <2484@coreit.co.kr>
Co-authored-by: SlimGary <trash.slim@gmail.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat: rename api routes and files

* feat: improve guacd ui/backend

* feat: improve guacd ui/backend

* fix: state persistance issues causing refresh

* feat: improge guacd connections, fixed telnet not opening, and improved general guacd integration

* feat: continue improving integration also with bug fixes

* Merge 2.0.0 with 2.0.0 that includes bug fixes (#620)

* Guacd, Docker-Compose, RDP (#475)

* fix select edit host but not update view (#438)

* fix: Checksum issue with chocolatey

* fix: Remove homebrew old stuff

* Add Korean translation (#439)

Co-authored-by: 송준우 <2484@coreit.co.kr>

* feat: Automate flatpak

* fix: Add imagemagik to electron builder to resolve build error

* fix: Build error with runtime repo flag

* fix: Flatpak runtime error and install freedesktop ver warning

* fix: Flatpak runtime error and install freedesktop ver warning

* feat: Re-add homebrew cask and move scripts to backend

* fix: No sandbox flag issue

* fix: Change name for electron macos cask output

* fix: Sandbox error with Linux

* fix: Remove comming soon for app stores in readme

* Adding Comment at the end of the public_key on the host on deploy (#440)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* -Add New Interface for Credential DB
-Add Credential Name as a comment into the server authorized_key file

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Sudo auto fill password (#441)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Feature Sudo password auto-fill;

* Fix locale json shema;

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Added Italian Language; (#445)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Added Italian Language;

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Auto collapse snippet folders (#448)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* feat: Add collapsable snippets (customizable in user profile)

* Translations (#447)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Added Italian Language;

* Fix translations;

Removed duplicate keys, synchronised other languages using English as the source, translated added keys, fixed inaccurate translations.

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* Remove PTY-level keepalive (#449)

* Add termix.rb Cask file

* Update Termix to version 1.9.0 with new checksum

* Update README to remove 'coming soon' notes

* Remove PTY-level keepalive to prevent unwanted terminal output; use SSH-level keepalive instead

---------

Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>

* feat: add Guacamole support for RDP, VNC, and Telnet connections

- Implemented WebSocket support for Guacamole in Nginx configuration.
- Added REST API endpoints for generating connection tokens and checking guacd status.
- Created Guacamole server using guacamole-lite for handling connections.
- Developed frontend components for testing RDP/VNC connections and displaying the remote session.
- Updated package dependencies to include guacamole-common-js and guacamole-lite.
- Enhanced logging for Guacamole operations.

* feat: enhance Guacamole support with RDP and VNC connection settings and UI updates

* feat: Seperate server stats and tunnel management (improved both UI's) then started initial docker implementation

* fix: finalize adding docker to db

* fix: merge syntax errors

* feat: implement mouse coordinate adjustment based on scale factor in GuacamoleDisplay

* feat: add TypeScript definitions for guacamole-common-js module

* feat: enhance Mouse.State constructor to accept optional parameters and object destructuring

* feat: Add support for RDP and VNC connections in SSH host management

- Introduced connectionType field to differentiate between SSH, RDP, VNC, and Telnet in host data structures.
- Updated backend routes to handle RDP/VNC specific fields: domain, security, and ignoreCert.
- Enhanced the HostManagerEditor to include RDP/VNC specific settings and authentication options.
- Implemented token retrieval for RDP/VNC connections using Guacamole API.
- Updated UI components to reflect connection type changes and provide appropriate connection buttons.
- Removed the GuacamoleTestDialog component as its functionality is integrated into the HostManagerEditor.
- Adjusted the TopNavbar and Host components to accommodate new connection types and their respective actions.

* feat: Enhance Guacamole integration with extended configuration options

- Added detailed Guacamole configuration interface for RDP/VNC/Telnet connections, including display, audio, performance, and session settings.
- Implemented logging for token requests and received options for better debugging.
- Updated HostManagerEditor to support new Guacamole configuration fields with validation and default values.
- Integrated Guacamole configuration parsing in HostManagerViewer and Host components.
- Enhanced API requests to include extended Guacamole configuration parameters in the token request.
- Refactored code to convert camelCase configuration keys to kebab-case for compatibility with Guacamole API.

* feat: merge guacd into 2.0.0 and improve UI for host manager and made general bug fixes

---------

Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: junu <bigdwarf_@naver.com>
Co-authored-by: 송준우 <2484@coreit.co.kr>
Co-authored-by: SlimGary <trash.slim@gmail.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat: rename api routes and files

* feat: improve guacd ui/backend

* feat: improve guacd ui/backend

* fix: state persistance issues causing refresh

* feat: improge guacd connections, fixed telnet not opening, and improved general guacd integration

* feat: continue improving integration also with bug fixes

---------

Co-authored-by: Wesley Reid <starhound@lostsouls.org>
Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com>
Co-authored-by: junu <bigdwarf_@naver.com>
Co-authored-by: 송준우 <2484@coreit.co.kr>
Co-authored-by: SlimGary <trash.slim@gmail.com>
Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat: allow customizing guacd backened url

* fix: ssh route mistmatching and guacamole url not changing

* chore: increment ver

* feat: change default to work with default compose, added splits creen support, updated readmes

* fix: linux app not starting due to better sqlite isuses, improved copy/paste system so no context menu, added oidc remember me toggle, improved OS detection for sessions, flatpak invalid key, and sharing hosts with other users errors

* fix: global settings not setting

* chore: update compose

* feat: improve the global status input

* chore: cleanup files

* chore: update export/improt with new host fields

* fix: file manager and docker not loading properly

---------

Co-authored-by: Wesley Reid <starhound@lostsouls.org>
Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com>
Co-authored-by: junu <bigdwarf_@naver.com>
Co-authored-by: 송준우 <2484@coreit.co.kr>
Co-authored-by: SlimGary <trash.slim@gmail.com>
Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Luke Gustafson
2026-03-14 20:05:05 -05:00
committed by GitHub
parent a255a08903
commit e9e30cd318
85 changed files with 7053 additions and 2286 deletions
@@ -17,7 +17,10 @@ import {
updatePasswordResetAllowed,
getGlobalMonitoringSettings,
updateGlobalMonitoringSettings,
getGuacamoleSettings,
updateGuacamoleSettings,
} from "@/ui/main-axios.ts";
import { Button } from "@/components/ui/button.tsx";
interface GeneralSettingsTabProps {
allowRegistration: boolean;
@@ -51,9 +54,10 @@ export function GeneralSettingsTab({
const [passwordLoginLoading, setPasswordLoginLoading] = React.useState(false);
const [passwordResetLoading, setPasswordResetLoading] = React.useState(false);
// Global monitoring defaults
const [statusInterval, setStatusInterval] = React.useState(60);
const [metricsInterval, setMetricsInterval] = React.useState(30);
const [statusInputValue, setStatusInputValue] = React.useState("60");
const [metricsInputValue, setMetricsInputValue] = React.useState("30");
const [statusUnit, setStatusUnit] = React.useState<"seconds" | "minutes">(
"seconds",
);
@@ -62,59 +66,101 @@ export function GeneralSettingsTab({
);
const [monitoringLoading, setMonitoringLoading] = React.useState(false);
const [guacEnabled, setGuacEnabled] = React.useState(true);
const [guacUrl, setGuacUrl] = React.useState("guacd:4822");
const [guacLoading, setGuacLoading] = React.useState(false);
React.useEffect(() => {
getGlobalMonitoringSettings()
getGuacamoleSettings()
.then((data) => {
setStatusInterval(data.statusCheckInterval);
setMetricsInterval(data.metricsInterval);
setGuacEnabled(data.enabled);
setGuacUrl(data.url);
})
.catch(() => {
// Use defaults silently
toast.error(t("admin.failedToLoadGuacamoleSettings"));
});
}, []);
}, [t]);
const saveMonitoringDebounce = React.useRef<NodeJS.Timeout | null>(null);
const saveGuacDebounce = React.useRef<NodeJS.Timeout | null>(null);
const saveMonitoringSettings = React.useCallback(
(newStatus: number, newMetrics: number) => {
if (saveMonitoringDebounce.current) {
clearTimeout(saveMonitoringDebounce.current);
const saveGuacSettings = React.useCallback(
(newEnabled: boolean, newUrl: string) => {
if (saveGuacDebounce.current) {
clearTimeout(saveGuacDebounce.current);
}
saveMonitoringDebounce.current = setTimeout(async () => {
setMonitoringLoading(true);
saveGuacDebounce.current = setTimeout(async () => {
setGuacLoading(true);
try {
await updateGlobalMonitoringSettings({
statusCheckInterval: newStatus,
metricsInterval: newMetrics,
});
toast.success(t("admin.globalSettingsSaved"));
} catch (error) {
const errorMessage =
error instanceof Error
? error.message
: t("admin.failedToSaveGlobalSettings");
toast.error(errorMessage);
await updateGuacamoleSettings({ enabled: newEnabled, url: newUrl });
toast.success(t("admin.guacamoleSettingsSaved"));
} catch {
toast.error(t("admin.failedToSaveGuacamoleSettings"));
} finally {
setMonitoringLoading(false);
setGuacLoading(false);
}
}, 800);
},
[t],
);
const handleStatusIntervalChange = (value: string) => {
const num = parseInt(value) || 0;
React.useEffect(() => {
getGlobalMonitoringSettings()
.then((data) => {
setStatusInterval(data.statusCheckInterval);
setMetricsInterval(data.metricsInterval);
setStatusInputValue(String(data.statusCheckInterval));
setMetricsInputValue(String(data.metricsInterval));
})
.catch(() => {
// Use defaults silently
});
}, []);
const saveMonitoringSettings = React.useCallback(
async (newStatus: number, newMetrics: number) => {
setMonitoringLoading(true);
try {
await updateGlobalMonitoringSettings({
statusCheckInterval: newStatus,
metricsInterval: newMetrics,
});
toast.success(t("admin.globalSettingsSaved"));
} catch (error) {
const errorMessage =
error instanceof Error
? error.message
: t("admin.failedToSaveGlobalSettings");
toast.error(errorMessage);
} finally {
setMonitoringLoading(false);
}
},
[t],
);
const handleStatusBlur = () => {
const num = parseInt(statusInputValue) || 0;
const seconds = statusUnit === "minutes" ? num * 60 : num;
const clamped = Math.max(5, Math.min(3600, seconds));
setStatusInterval(clamped);
setStatusInputValue(
statusUnit === "minutes"
? String(Math.round(clamped / 60))
: String(clamped),
);
saveMonitoringSettings(clamped, metricsInterval);
};
const handleMetricsIntervalChange = (value: string) => {
const num = parseInt(value) || 0;
const handleMetricsBlur = () => {
const num = parseInt(metricsInputValue) || 0;
const seconds = metricsUnit === "minutes" ? num * 60 : num;
const clamped = Math.max(5, Math.min(3600, seconds));
setMetricsInterval(clamped);
setMetricsInputValue(
metricsUnit === "minutes"
? String(Math.round(clamped / 60))
: String(clamped),
);
saveMonitoringSettings(statusInterval, clamped);
};
@@ -244,12 +290,9 @@ export function GeneralSettingsTab({
<div className="flex gap-2 mt-1">
<Input
type="number"
value={
statusUnit === "minutes"
? Math.round(statusInterval / 60)
: statusInterval
}
onChange={(e) => handleStatusIntervalChange(e.target.value)}
value={statusInputValue}
onChange={(e) => setStatusInputValue(e.target.value)}
onBlur={handleStatusBlur}
disabled={monitoringLoading}
className="flex-1"
/>
@@ -257,6 +300,11 @@ export function GeneralSettingsTab({
value={statusUnit}
onValueChange={(value: "seconds" | "minutes") => {
setStatusUnit(value);
setStatusInputValue(
value === "minutes"
? String(Math.round(statusInterval / 60))
: String(statusInterval),
);
}}
>
<SelectTrigger className="w-[120px]">
@@ -280,12 +328,9 @@ export function GeneralSettingsTab({
<div className="flex gap-2 mt-1">
<Input
type="number"
value={
metricsUnit === "minutes"
? Math.round(metricsInterval / 60)
: metricsInterval
}
onChange={(e) => handleMetricsIntervalChange(e.target.value)}
value={metricsInputValue}
onChange={(e) => setMetricsInputValue(e.target.value)}
onBlur={handleMetricsBlur}
disabled={monitoringLoading}
className="flex-1"
/>
@@ -293,6 +338,11 @@ export function GeneralSettingsTab({
value={metricsUnit}
onValueChange={(value: "seconds" | "minutes") => {
setMetricsUnit(value);
setMetricsInputValue(
value === "minutes"
? String(Math.round(metricsInterval / 60))
: String(metricsInterval),
);
}}
>
<SelectTrigger className="w-[120px]">
@@ -311,6 +361,55 @@ export function GeneralSettingsTab({
</div>
</div>
</div>
<div className="rounded-lg border-2 border-border bg-card p-4 space-y-4">
<h3 className="text-lg font-semibold">
{t("admin.guacamoleIntegration")}
</h3>
<p className="text-sm text-muted-foreground">
{t("admin.guacamoleIntegrationDesc")}
</p>
<Button
variant="outline"
size="sm"
className="h-8 px-3 text-xs"
onClick={() =>
window.open("https://docs.termix.site/remote-desktop", "_blank")
}
>
{t("common.documentation")}
</Button>
<label className="flex items-center gap-2">
<Checkbox
checked={guacEnabled}
onCheckedChange={(checked) => {
const val = checked === true;
setGuacEnabled(val);
saveGuacSettings(val, guacUrl);
}}
disabled={guacLoading}
/>
{t("admin.enableGuacamole")}
</label>
{guacEnabled && (
<div>
<label className="text-sm font-medium">{t("admin.guacdUrl")}</label>
<Input
className="mt-1"
value={guacUrl}
placeholder={t("admin.guacdUrlPlaceholder")}
disabled={guacLoading}
onChange={(e) => {
setGuacUrl(e.target.value);
saveGuacSettings(guacEnabled, e.target.value);
}}
/>
<p className="text-xs text-muted-foreground mt-1">
{t("admin.guacdUrlNote")}
</p>
</div>
)}
</div>
</div>
);
}