Skip to content

Native proxy settings - #32804

Closed
tim2zg wants to merge 22 commits into
element-hq:developfrom
tim2zg:feat/native-proxy-settings
Closed

tim2zg wants to merge 22 commits into
element-hq:developfrom
tim2zg:feat/native-proxy-settings

Conversation

@tim2zg

@tim2zg tim2zg commented Mar 14, 2026 •

Copy link
Copy Markdown

Fixes #32407

Checklist

Fixes #32407

@tim2zg
tim2zg requested a review from a team as a code owner March 14, 2026 22:47
@tim2zg
tim2zg requested review from Half-Shot and dbkr March 14, 2026 22:47
@github-actions github-actions Bot added the Z-Community-PR Issue is solved by a community member's PR label Mar 14, 2026

@Half-Shot Half-Shot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks for the contribution! Unfortunately you've caught us in the mid-transition phase to MVVM so the changes are going to need a small shuffle. I think basically this involves moving the component to shared-components, and building up a view model for interfacing with Settings.

The other bits of the code are looking good, thanks for a good start

Comment thread apps/web/src/@types/global.d.ts Outdated
@@ -65,6 +65,7 @@ type ElectronChannel =
| "userDownloadCompleted"
| "userDownloadAction"
| "openDesktopCapturerSourcePicker"
| "open_proxy_settings"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably follow the same casing

Suggested change
| "open_proxy_settings"
| "openProxySettings"

private renderProxySection(): ReactNode {
if (!window.electron) return null;

const config = SettingsStore.getValue("desktopProxyConfig") || { mode: "system" };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should { mode: "system" } just be a default value of desktopProxyConfig? It does support defaults

@@ -294,6 +296,36 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
);
}

private renderProxySection(): ReactNode {
if (!window.electron) return null;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use the Platform code for this. E.g. exposing a supportsProxyConfiguration() like https://github.com/vector-im/riot-web/blob/da5a30ba7130f763f9b324bb1e2c68377cf728bb/apps/web/src/BasePlatform.ts#L162-L169.

And then it's just a case of PlatformPeg.get().supportsProxyConfiguration() which is a bit more generic than checking if electron is exposed.

Comment thread apps/web/src/components/views/settings/NetworkProxyModal.tsx
const update = (patch: Partial<ProxyConfig>): void => setConfig((prev) => ({ ...prev, ...patch }));

return (
<FocusLock

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think here you can just use BaseDialog, with the above suggestion about view models, I'd do:

export const NetworkProxyModal: React.FC<Props> = ({ onFinished }) => {
  const vm = new NetworkProxyViewModel();
  return <BaseDialog {...}>
      <NetworkProxyModalView vm={vm} />
  </BaseDialog>
}

Comment thread apps/web/src/i18n/strings/de_DE.json Outdated
@@ -472,6 +472,7 @@
"cameras": "Kameras",
"cancel": "Abbrechen",
"capabilities": "Funktionen",
"configuration": "Konfiguration",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, another one of our footguns. We don't accept translations directly into the codebase even if you know the translations, it has to go via Localazy unless it's en_EN.json.

Comment thread apps/web/src/settings/Settings.tsx Outdated
@@ -1463,4 +1465,8 @@ export const SETTINGS: Settings = {
displayName: _td("devtools|settings|elementCallUrl"),
default: "",
},
"desktopProxyConfig": {
supportedLevels: [SettingLevel.PLATFORM],
default: { mode: "system" } as ProxyConfig,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't need an as?

@CLAassistant

CLAassistant commented Mar 17, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@tim2zg
tim2zg force-pushed the feat/native-proxy-settings branch 2 times, most recently from e1d52f8 to c5a662f Compare March 17, 2026 10:59
@Half-Shot
Half-Shot self-requested a review March 17, 2026 11:00
- Ported modal logic to NetworkProxyViewModel and view to NetworkProxyView in shared-components
- Implemented real logic for supportsProxyConfiguration in ElectronPlatform
- Renamed open_proxy_settings to openProxySettings for consistent casing
- Removed German translations (to be handled via Localazy)
- Registered desktopProxyConfig in SettingsStore
- Simplified NetworkProxyModal by utilizing the new MVVM components and BaseDialog
@tim2zg
tim2zg force-pushed the feat/native-proxy-settings branch from c5a662f to ea1bb74 Compare March 17, 2026 14:33
@tim2zg

tim2zg commented Mar 17, 2026

Copy link
Copy Markdown
Author

Thank you for the feedback and guidance.
I'm still getting familiar with the React/MVVM, so please let me know if there are any further refinements / or corrections needed.

tim2zg and others added 5 commits March 22, 2026 10:53
- Added Network Proxy link to AuthFooter for pre-login configuration
- Ensured proxy settings survive logout
- Improved proxy rule generation for HTTPS support
- Cleaned up MVVM implementation and translations
- Ported all desktop-side proxy fixes to apps/desktop
- Verified MVVM migration and auth footer entry
- Ensured consistent IPC naming and platform abstraction
- Fixed duplicate imports and globalThis usage in electron-main
@Half-Shot Half-Shot added the T-Feature Request to add a new feature which does not exist right now label Apr 27, 2026
@Half-Shot Half-Shot removed the T-Feature Request to add a new feature which does not exist right now label May 28, 2026
@Half-Shot
Half-Shot requested review from a team, Half-Shot and t3chguy and removed request for a team, Half-Shot and dbkr June 4, 2026 09:08
Comment on lines +14 to +28
export interface NetworkProxyViewModelProps {
initialConfig: {
mode: "system" | "direct" | "custom";
scheme?: string;
host?: string;
port?: number;
username?: string;
password?: string;
bypass?: string;
};
onSave: (config: any) => Promise<void>;
onCancel: () => void;
}

export class NetworkProxyViewModel

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jsdoc all props & the class overall please

});
this.snapshot.merge({ hasChanges: false, loading: false });
} catch (e) {
this.snapshot.merge({ error: String(e), loading: false });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks to set error to an untranslated "raw" error string, but later it is rendered plainly, which means it will not be i18n'd and may not be in the right language for the user


{error && (
<Text size="sm" className={styles.errorText}>
{error}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to render an untranslated error

Comment on lines +141 to +143
<option value="http">HTTP</option>
<option value="https">HTTPS</option>
<option value="socks5">SOCKS5</option>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i18n please, some languages have preferences for non-english terms

Comment thread apps/web/src/BasePlatform.ts Outdated

/**
* Returns true if the platform supports network proxy configuration.
* @returns {boolean} whether the platform supports proxy configuration

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the type is superfluous, no point duplicating between jsdoc & typescript

Comment thread apps/web/src/i18n/strings/en_EN.json Outdated
"mode_direct_selected": "Direct connection is enabled. No proxy will be used.",
"mode_system_selected": "Using the system proxy configuration.",
"no_proxy_direct": "No proxy (direct connection)",
"no_proxy_for_comma_separated": "No proxy for",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use a placeholder for the remainder of the sentence, to allow effective i18n

Comment thread apps/desktop/src/electron-main.ts
@tim2zg tim2zg changed the title Feat/native proxy settings Feat/native proxy settings Fixes https://github.com/element-hq/element-web/issues/32407 Jun 6, 2026
@tim2zg

tim2zg commented Jun 6, 2026

Copy link
Copy Markdown
Author

still testing

Comment on lines -542 to -543
} else {
global.mainWindow?.webContents.send("openDesktopCapturerSourcePicker");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seem unintentional

Comment thread apps/desktop/src/electron-main.ts Outdated
app.exit(1);
}

void global.mainWindow.loadURL("vector://vector/webapp/");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seem unintentional

label: _t("action|zoom_out"),
},
{ type: "separator" },
// in macOS the Preferences menu item goes in the first menu

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a comment like this is still worthwhile, just updated to match the changes would be good

@Half-Shot Half-Shot changed the title Feat/native proxy settings Fixes https://github.com/element-hq/element-web/issues/32407 Feat/native proxy settings Jun 11, 2026
@langleyd

Copy link
Copy Markdown
Member

Hey @tim2zg, thanks for your contribution. Are you still working on this? If not, we will close it to remove it from our review list and you'll be free to open it again when you are ready.

@tim2zg

tim2zg commented Jun 25, 2026

Copy link
Copy Markdown
Author

Sorry for the delay! Is it fine to leave the proxy UI as is? I tried getting the username/password fields to be the exact same width but it was a bit of a pain to override the Compound components.

image

@Half-Shot
Half-Shot requested a review from t3chguy July 9, 2026 09:11
@t3chguy
t3chguy requested a review from a team July 20, 2026 12:38
Comment on lines +152 to +206
.networkProxyView button:not([data-kind]) {
border: none !important;
background: transparent !important;
padding: 0 !important;
margin: 0 !important;
height: auto !important;
width: auto !important;
border-radius: initial !important;
box-shadow: none !important;
}

.passwordInput {
display: inline-flex !important;
position: relative !important;
width: 100% !important;
border: 1px solid var(--cpd-color-border-interactive-primary) !important;
border-radius: 8px !important;
background: var(--cpd-color-bg-canvas-default) !important;
box-sizing: border-box !important;
align-items: center !important;
}

.passwordInput input {
margin: 0 !important;
border: none !important;
background: transparent !important;
padding: var(--cpd-space-3x) var(--cpd-space-12x) var(--cpd-space-3x) var(--cpd-space-4x) !important;
width: 100% !important;
color: var(--cpd-color-text-primary) !important;
box-sizing: border-box !important;
font: inherit !important;
}

.passwordInput button {
display: flex !important;
align-items: center !important;
justify-content: center !important;
position: absolute !important;
right: var(--cpd-space-2x) !important;
top: 0 !important;
bottom: 0 !important;
height: 100% !important;
width: var(--cpd-space-8x) !important;
padding: 0 !important;
margin: 0 !important;
background: transparent !important;
border: none !important;
cursor: pointer !important;
box-shadow: none !important;
}

.passwordInput:focus-within {
outline: 2px solid var(--cpd-color-border-focused) !important;
border-color: transparent !important;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wall of !important seems really off, we should only use !important where absolutely necessary and rely on layering and other techniques to avoid it where possible

onChange={() => vm.updateScheme(p)}
className={styles.hiddenRadio}
/>
<Text as="span">{_t(`settings|network_proxy|protocol_${p}` as any)}</Text>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah lets not use as any here - it voids the intentional type protection here

_td("settings|network_proxy|protocol_http");
_td("settings|network_proxy|protocol_https");
_td("settings|network_proxy|protocol_socks5");
_td("settings|network_proxy|requires_auth");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah please do not do this, add a method which maps "http" | "https" | "socks5" to a translated string instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this test be written using vitest instead?

Comment thread apps/desktop/src/store.ts

Store.instance?.clear();

// Restore proxy settings after clear so they survive logout

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really a good idea? On a shared computer this could leave credentials for an authenticated proxy in situ

@americanrefugee americanrefugee left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a proper design for the menu with Compound components:

Image

Total width of the modal (including glass border) should be 520px.

Please make sure all fields, text, and colors are Compound components (the password field you're using looks wrong).

@richvdh richvdh changed the title Feat/native proxy settings Native proxy settings Jul 23, 2026
@richvdh

richvdh commented Jul 23, 2026

Copy link
Copy Markdown
Member

A 1000-line patch is indeed a "feat", but I don't think that's what was meant...

@t3chguy

t3chguy commented Jul 27, 2026

Copy link
Copy Markdown
Member

@tim2zg please click the re-request review when this is ready for another review, also include up to date screenshots please.

@tim2zg

tim2zg commented Jul 27, 2026

Copy link
Copy Markdown
Author

Sure thank you:)

@t3chguy

t3chguy commented Aug 13, 2026

Copy link
Copy Markdown
Member

Closing due to changes not having been made to comply with the requests made by design. Feel free to open a new PR once you have made the asked changes

@t3chguy t3chguy closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-Enhancement Z-Community-PR Issue is solved by a community member's PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add UI for setting HTTP proxy to desktop app

9 participants