feat: redesign user host defaults system

This commit is contained in:
LukeGus committed 2026-09-30 06:19:56 -05:00
1 parent 3028ab1176
commit a4a4d4f27b
144 files changed
+24609 -2555

No files matched your search

+3 -1
View File
@@ -323,7 +323,9 @@
"enableToolbar": {
"label": "Remote desktop toolbar",
"description": "Show the toolbar in RDP, VNC and Telnet sessions."
}
},
"displayGroup": "Display",
"displayDefaultsTab": "Remote Desktop"
}
},
"palette": {
+293 -18
View File
@@ -150,7 +150,8 @@
"labelKey": "settings.user.colorDepth32"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "resizeMethod",
@@ -172,7 +173,8 @@
"labelKey": "settings.user.resizeReconnect"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "forceLossless",
@@ -194,7 +196,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "enableWallpaper",
@@ -216,7 +219,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "enableFontSmoothing",
@@ -238,7 +242,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "enableDesktopComposition",
@@ -260,7 +265,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "disableAudio",
@@ -282,7 +288,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "enablePrinting",
@@ -304,7 +311,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "enableDrive",
@@ -326,7 +334,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "disableCopy",
@@ -348,7 +357,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
},
{
"key": "disablePaste",
@@ -370,7 +380,8 @@
"labelKey": "settings.user.off"
}
],
"default": "inherit"
"default": "inherit",
"hidden": true
}
],
"host": {
@@ -380,21 +391,24 @@
"type": "boolean",
"labelKey": "settings.host.enableRdp.label",
"default": false,
"hidden": true
"hidden": true,
"defaultable": false
},
{
"key": "enableVnc",
"type": "boolean",
"labelKey": "settings.host.enableVnc.label",
"default": false,
"hidden": true
"hidden": true,
"defaultable": false
},
{
"key": "enableTelnet",
"type": "boolean",
"labelKey": "settings.host.enableTelnet.label",
"default": false,
"hidden": true
"hidden": true,
"defaultable": false
},
{
"key": "rdpPort",
@@ -403,7 +417,8 @@
"min": 1,
"max": 65535,
"default": 3389,
"hidden": true
"hidden": true,
"defaultable": false
},
{
"key": "vncPort",
@@ -412,7 +427,8 @@
"min": 1,
"max": 65535,
"default": 5900,
"hidden": true
"hidden": true,
"defaultable": false
},
{
"key": "telnetPort",
@@ -421,7 +437,8 @@
"min": 1,
"max": 65535,
"default": 23,
"hidden": true
"hidden": true,
"defaultable": false
},
{
"key": "rdpSecurity",
@@ -444,7 +461,8 @@
"default": {},
"hidden": true,
"shareRead": "edit",
"secretKeys": ["gateway-password"]
"secretKeys": ["gateway-password"],
"defaultable": false
},
{
"key": "enableToolbar",
@@ -453,6 +471,263 @@
"descriptionKey": "settings.host.enableToolbar.description",
"default": true,
"hidden": true
},
{
"key": "colorDepth",
"type": "select",
"labelKey": "settings.user.colorDepth.label",
"descriptionKey": "settings.user.colorDepth.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "16",
"labelKey": "settings.user.colorDepth16"
},
{
"value": "24",
"labelKey": "settings.user.colorDepth24"
},
{
"value": "32",
"labelKey": "settings.user.colorDepth32"
}
],
"default": "inherit",
"personal": true
},
{
"key": "resizeMethod",
"type": "select",
"labelKey": "settings.user.resizeMethod.label",
"descriptionKey": "settings.user.resizeMethod.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "display-update",
"labelKey": "settings.user.resizeDisplayUpdate"
},
{
"value": "reconnect",
"labelKey": "settings.user.resizeReconnect"
}
],
"default": "inherit",
"personal": true
},
{
"key": "forceLossless",
"type": "select",
"labelKey": "settings.user.forceLossless.label",
"descriptionKey": "settings.user.forceLossless.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "enableWallpaper",
"type": "select",
"labelKey": "settings.user.enableWallpaper.label",
"descriptionKey": "settings.user.enableWallpaper.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "enableFontSmoothing",
"type": "select",
"labelKey": "settings.user.enableFontSmoothing.label",
"descriptionKey": "settings.user.enableFontSmoothing.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "enableDesktopComposition",
"type": "select",
"labelKey": "settings.user.enableDesktopComposition.label",
"descriptionKey": "settings.user.enableDesktopComposition.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "disableAudio",
"type": "select",
"labelKey": "settings.user.disableAudio.label",
"descriptionKey": "settings.user.disableAudio.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "enablePrinting",
"type": "select",
"labelKey": "settings.user.enablePrinting.label",
"descriptionKey": "settings.user.enablePrinting.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "enableDrive",
"type": "select",
"labelKey": "settings.user.enableDrive.label",
"descriptionKey": "settings.user.enableDrive.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "disableCopy",
"type": "select",
"labelKey": "settings.user.disableCopy.label",
"descriptionKey": "settings.user.disableCopy.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
},
{
"key": "disablePaste",
"type": "select",
"labelKey": "settings.user.disablePaste.label",
"descriptionKey": "settings.user.disablePaste.description",
"group": "settings.host.displayGroup",
"options": [
{
"value": "inherit",
"labelKey": "settings.user.inherit"
},
{
"value": "on",
"labelKey": "settings.user.on"
},
{
"value": "off",
"labelKey": "settings.user.off"
}
],
"default": "inherit",
"personal": true
}
]
}
@@ -177,7 +177,7 @@ export function hostPayloadLegacy(
return Object.keys(out).length > 0 ? out : null;
}
/** User setting key to the guacd parameter it sets. */
/** Display field key to the guacd parameter it sets. */
const USER_DEFAULT_PARAMS: Record<string, string> = {
colorDepth: "color-depth",
resizeMethod: "resize-method",
@@ -193,8 +193,8 @@ const USER_DEFAULT_PARAMS: Record<string, string> = {
};
/**
* The user's RDP defaults as guacd parameters. "inherit" leaves a parameter
* to the host and guacd; on and off become booleans.
* Display settings as guacd parameters. "inherit" leaves a parameter to the
* host and guacd; on and off become booleans.
*/
export function userDefaultParams(
values: Record<string, unknown>,
@@ -215,9 +215,22 @@ export function userDefaultParams(
return params;
}
export async function readUserDefaults(
/**
* The display settings a session runs with, as guacd parameters: the host's
* as this user sees them (their own defaults while the host follows its
* defaults), or with no host, this user's defaults.
*/
export async function readDisplayDefaults(
ctx: PluginContext,
userId: string,
hostId?: number,
): Promise<Record<string, unknown>> {
return userDefaultParams(await ctx.settings.getAll("user", userId));
const values: Record<string, unknown> = {};
for (const key of Object.keys(USER_DEFAULT_PARAMS)) {
values[key] =
hostId === undefined
? await ctx.settings.getHostDefault(userId, key)
: await ctx.settings.getHostFor(hostId, userId, key);
}
return userDefaultParams(values);
}
+9 -5
View File
@@ -23,7 +23,7 @@ import {
PORT_KEY,
isRemoteProtocol,
readHostSettings,
readUserDefaults,
readDisplayDefaults,
type RemoteProtocol,
} from "./host-settings.js";
import { errorMessage, type RemoteDesktopLogger } from "./log.js";
@@ -203,7 +203,7 @@ export function registerRoutes(router: Router, deps: RouteDeps): void {
const userId = ctx.currentActor();
if (type === "rdp" && userId) {
for (const [key, value] of Object.entries(
await readUserDefaults(ctx, userId),
await readDisplayDefaults(ctx, userId),
)) {
if (isServerOwnedSetting(key)) continue;
if (options[key] === undefined) options[key] = value;
@@ -319,9 +319,11 @@ export function registerRoutes(router: Router, deps: RouteDeps): void {
});
}
// The user's RDP defaults sit under whatever the host sets itself.
// The display settings sit under whatever the host's guacd settings say.
const { config, guacdOverrides } = cleanGuacConfig({
...(protocol === "rdp" ? await readUserDefaults(ctx, userId) : {}),
...(protocol === "rdp"
? await readDisplayDefaults(ctx, userId, hostId)
: {}),
...settings.guacamoleConfig,
});
let guacConfig = config;
@@ -545,7 +547,9 @@ export function registerRoutes(router: Router, deps: RouteDeps): void {
.json({ error: "Protocol is not enabled for this host" });
}
const { guacdOverrides } = cleanGuacConfig({
...(protocol === "rdp" ? await readUserDefaults(ctx, userId) : {}),
...(protocol === "rdp"
? await readDisplayDefaults(ctx, userId, hostId)
: {}),
...settings.guacamoleConfig,
});
guacd = {
@@ -17,6 +17,7 @@ import {
} from "@termix/plugin-sdk/frontend";
import {
FakeSwitch,
HostFeatureFields,
SectionCard,
SettingRow,
isElectron,
@@ -166,6 +167,7 @@ function ToolbarCard({
<SettingRow
label={t("settings.host.enableToolbar.label")}
description={t("settings.host.enableToolbar.description")}
defaultKey="enableToolbar"
>
<FakeSwitch
checked={form.enableToolbar}
@@ -254,6 +256,27 @@ function TelnetSection(props: HostEditorSectionProps) {
);
}
/**
* The defaults editor's remote desktop section: the display settings and the
* toolbar, which every host follows unless its own guacd settings say
* otherwise. A host edits these in its protocol tabs instead.
*/
function DisplayDefaultsSection(props: HostEditorSectionProps) {
const { t } = useTranslation();
const { form, setField } = remoteDesktopForm(props);
return (
<>
<SectionCard
title={t("settings.host.displayGroup")}
icon={<Monitor className="size-3.5" />}
>
<HostFeatureFields form={props.form} updateForm={props.updateForm} />
</SectionCard>
<ToolbarCard form={form} setField={setField} />
</>
);
}
const SECTIONS: Record<Protocol, ComponentType<HostEditorSectionProps>> = {
rdp: RdpSection,
vnc: VncSection,
@@ -343,6 +366,16 @@ function registerHostSurfaces(app: TermixApp): void {
});
}
app.registerHostEditorSection({
id: "remote-desktop-display",
group: "top",
titleKey: "settings.host.displayDefaultsTab",
icon: Monitor,
order: 40,
defaults: "only",
component: DisplayDefaultsSection,
});
if (isElectron()) registerNativeRdp(app);
}
@@ -149,14 +149,15 @@ describe("POST /connect-host/:hostId", () => {
});
});
it("puts the user's RDP defaults under the host's own values", async () => {
it("puts the host's display settings under its own guacd settings", async () => {
server = await start({ protocolTargets: { "7:rdp": target() } });
await server.mock.ctx.settings.setHost(7, "enableRdp", true);
await server.mock.ctx.settings.setHost(7, "guacamoleConfig", {
"color-depth": 32,
});
await server.mock.ctx.settings.setUser("user-1", "colorDepth", "16");
await server.mock.ctx.settings.setUser("user-1", "disableCopy", "on");
// What the host follows from its defaults.
await server.mock.ctx.settings.setHost(7, "colorDepth", "16");
await server.mock.ctx.settings.setHost(7, "disableCopy", "on");
const response = await server.request("POST", "/connect-host/7", {
protocol: "rdp",