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

@@ -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);
}