Skip to content

Commit 5ff536e

Browse files
authored
Merge pull request #172 from open-webui/main
0.0.17
2 parents c0e463b + 842c148 commit 5ff536e

6 files changed

Lines changed: 112 additions & 35 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.0.17] - 2026-05-03
9+
10+
### Added
11+
12+
- **Webview Context Menu.** Right-clicking inside the webview now shows a native context menu with Cut, Copy, Paste, Undo/Redo, spell-check suggestions, and "Open Link in Browser" — enabling system autofill and password manager integration on login pages (#161).
13+
14+
### Changed
15+
16+
- **Windows OpenSSL Compatibility.** The bundled Python's directory is now prepended to `PATH` on Windows so its own OpenSSL DLLs are loaded before any conflicting system-wide installations (Git for Windows, Anaconda, Strawberry Perl, etc.), preventing the `OPENSSL_Uplink: no OPENSSL_Applink` crash on startup (#167).
17+
- **Links Open in Default Browser on Windows.** Added `allowpopups` to the webview so that `target="_blank"` link clicks correctly propagate to the main process handler and open in the default browser instead of being silently blocked (#165, #170).
18+
- **Linux System Requirements.** Documentation now specifies glibc 2.28+ as a minimum requirement for Linux installations.
19+
820
## [0.0.16] - 2026-05-02
921

1022
### Fixed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Use both at the same time.
5454
|--|-------------|-------------|
5555
| **Disk** | 5 GB+ | ~500 MB |
5656
| **RAM** | 16 GB+ | 4 GB |
57-
| **OS** | macOS 12+, Windows 10+, modern Linux | Same |
57+
| **OS** | macOS 12+, Windows 10+, modern Linux (glibc 2.28+) | Same |
5858

5959
> [!NOTE]
6060
> Local models need serious RAM (7B ≈ 8 GB, 13B ≈ 16 GB). Lighter machine? Connect to a remote server instead.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "open-webui",
3-
"version": "0.0.16",
3+
"version": "0.0.17",
44
"license": "AGPL-3.0",
55
"description": "Open WebUI Desktop",
66
"main": "./out/main/index.js",

src/main/index.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,61 @@ if (!gotTheLock) {
12721272
// Malformed URL — let it through so Chromium can handle/reject it
12731273
}
12741274
})
1275+
1276+
// ── Native right-click context menu (#161) ──────────────────
1277+
// Electron <webview> guests don't show a context menu by default,
1278+
// which blocks right-click → Paste / Autofill / password-manager
1279+
// integration on login pages. Build a native menu with standard
1280+
// editing actions, spell-check suggestions, and link handling.
1281+
contents.on('context-menu', (_event, params) => {
1282+
const menuItems: Electron.MenuItemConstructorOptions[] = []
1283+
1284+
// Spell-check suggestions (if any)
1285+
if (params.misspelledWord && params.dictionarySuggestions?.length) {
1286+
for (const suggestion of params.dictionarySuggestions) {
1287+
menuItems.push({
1288+
label: suggestion,
1289+
click: () => contents.replaceMisspelling(suggestion)
1290+
})
1291+
}
1292+
menuItems.push({ type: 'separator' })
1293+
}
1294+
1295+
// Link handling
1296+
if (params.linkURL) {
1297+
menuItems.push({
1298+
label: 'Open Link in Browser',
1299+
click: () => openUrl(params.linkURL)
1300+
})
1301+
menuItems.push({
1302+
label: 'Copy Link',
1303+
click: () => clipboard.writeText(params.linkURL)
1304+
})
1305+
menuItems.push({ type: 'separator' })
1306+
}
1307+
1308+
// Editable field actions (input, textarea, contenteditable)
1309+
if (params.isEditable) {
1310+
menuItems.push(
1311+
{ label: 'Undo', role: 'undo', enabled: params.editFlags.canUndo },
1312+
{ label: 'Redo', role: 'redo', enabled: params.editFlags.canRedo },
1313+
{ type: 'separator' },
1314+
{ label: 'Cut', role: 'cut', enabled: params.editFlags.canCut },
1315+
{ label: 'Copy', role: 'copy', enabled: params.editFlags.canCopy },
1316+
{ label: 'Paste', role: 'paste', enabled: params.editFlags.canPaste },
1317+
{ label: 'Select All', role: 'selectAll', enabled: params.editFlags.canSelectAll }
1318+
)
1319+
} else if (params.selectionText) {
1320+
// Non-editable text selection
1321+
menuItems.push(
1322+
{ label: 'Copy', role: 'copy', enabled: params.editFlags.canCopy }
1323+
)
1324+
}
1325+
1326+
if (menuItems.length > 0) {
1327+
Menu.buildFromTemplate(menuItems).popup()
1328+
}
1329+
})
12751330
}
12761331
})
12771332

src/main/utils/index.ts

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,7 @@ export const installPython = async (installationDir?: string, onStatus?: (status
318318
['-m', 'pip', 'install', 'uv'],
319319
{
320320
encoding: 'utf-8',
321-
env: {
322-
...process.env,
323-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
324-
}
321+
env: pythonEnv()
325322
},
326323
(error) => {
327324
if (error) reject(error)
@@ -350,6 +347,38 @@ export const getPythonPath = (installationDir?: string) => {
350347
return path.normalize(getPythonExecutablePath(installationDir || getPythonInstallationDir()))
351348
}
352349

350+
/**
351+
* Build a process environment suitable for running the bundled Python.
352+
*
353+
* On Windows the standalone Python distribution ships its own OpenSSL DLLs
354+
* (`libssl-3-x64.dll`, `libcrypto-3-x64.dll`) next to `python.exe`. If a
355+
* different OpenSSL installation (Git for Windows, Anaconda, Strawberry Perl,
356+
* etc.) appears earlier on the system `PATH`, Python picks up those mismatched
357+
* DLLs at load-time, which causes the fatal error:
358+
*
359+
* OPENSSL_Uplink(..., 08): no OPENSSL_Applink
360+
*
361+
* To prevent this we prepend the Python installation directory to `PATH` so
362+
* Windows finds the correct DLLs first. On non-Windows platforms this is a
363+
* harmless no-op.
364+
*
365+
* Any additional env overrides (e.g. `configEnvVars`) can be spread after
366+
* calling this helper.
367+
*/
368+
const pythonEnv = (extra: Record<string, string> = {}): Record<string, string> => {
369+
const base: Record<string, string> = { ...process.env }
370+
371+
if (process.platform === 'win32') {
372+
// python.exe lives at the root of the installation directory on Windows
373+
const pythonDir = getPythonInstallationDir()
374+
const currentPath = process.env['PATH'] || process.env['Path'] || ''
375+
base['PATH'] = `${pythonDir};${currentPath}`
376+
base['PYTHONIOENCODING'] = 'utf-8'
377+
}
378+
379+
return { ...base, ...extra }
380+
}
381+
353382
export const isPythonInstalled = (installationDir?: string) => {
354383
const pythonPath = getPythonPath(installationDir)
355384
if (!fs.existsSync(pythonPath)) {
@@ -358,10 +387,7 @@ export const isPythonInstalled = (installationDir?: string) => {
358387
try {
359388
const pythonVersion = execFileSync(pythonPath, ['--version'], {
360389
encoding: 'utf-8',
361-
env: {
362-
...process.env,
363-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
364-
}
390+
env: pythonEnv()
365391
})
366392
log.info('Installed Python Version:', pythonVersion.trim())
367393
return true
@@ -375,10 +401,7 @@ export const isUvInstalled = (installationDir?: string) => {
375401
try {
376402
const result = execFileSync(pythonPath, ['-m', 'uv', '--version'], {
377403
encoding: 'utf-8',
378-
env: {
379-
...process.env,
380-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
381-
}
404+
env: pythonEnv()
382405
})
383406
log.info('Installed uv Version:', result.trim())
384407
return true
@@ -428,10 +451,7 @@ export const installPackage = (packageName: string, version?: string, onStatus?:
428451
...(version ? [`${packageName}==${version}`] : [packageName, '-U'])
429452
],
430453
{
431-
env: {
432-
...process.env,
433-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
434-
}
454+
env: pythonEnv()
435455
}
436456
)
437457

@@ -486,10 +506,7 @@ export const isPackageInstalled = (packageName: string): boolean => {
486506
try {
487507
const info = execFileSync(pythonPath, ['-m', 'uv', 'pip', 'show', packageName], {
488508
encoding: 'utf-8',
489-
env: {
490-
...process.env,
491-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
492-
}
509+
env: pythonEnv()
493510
})
494511
return info.includes(`Name: ${packageName}`)
495512
} catch {
@@ -503,10 +520,7 @@ export const getPackageVersion = (packageName: string): string | null => {
503520
try {
504521
const info = execFileSync(pythonPath, ['-m', 'uv', 'pip', 'show', packageName], {
505522
encoding: 'utf-8',
506-
env: {
507-
...process.env,
508-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
509-
}
523+
env: pythonEnv()
510524
})
511525
const match = info.match(/^Version:\s*(.+)$/m)
512526
return match ? match[1].trim() : null
@@ -521,10 +535,7 @@ export const uninstallPackage = (packageName: string): boolean => {
521535
try {
522536
execFileSync(pythonPath, ['-m', 'uv', 'pip', 'uninstall', packageName], {
523537
encoding: 'utf-8',
524-
env: {
525-
...process.env,
526-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
527-
}
538+
env: pythonEnv()
528539
})
529540
log.info(`Uninstalled package: ${packageName}`)
530541
return true
@@ -588,14 +599,12 @@ export const startServer = async (
588599
name: 'xterm-256color',
589600
cols: 200,
590601
rows: 50,
591-
env: {
592-
...process.env,
602+
env: pythonEnv({
593603
...(configEnvVars ?? {}),
594604
DATA_DIR: dataDir,
595605
WEBUI_SECRET_KEY: secretKey,
596-
PYTHONUNBUFFERED: '1',
597-
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
598-
}
606+
PYTHONUNBUFFERED: '1'
607+
})
599608
})
600609
} catch (error) {
601610
throw new Error(

src/renderer/src/lib/components/Main/Connections/Content.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@
270270
style="display: {view === 'connected' && activeConnectionId === connId ? 'flex' : 'none'}"
271271
partition="persist:connection-{connId}"
272272
preload={contentPreloadPath}
273+
allowpopups
273274
></webview>
274275
{/each}
275276

0 commit comments

Comments
 (0)