mirror of
https://github.com/open-webui/desktop.git
synced 2026-07-09 16:00:43 +00:00
Merge pull request #172 from open-webui/main
Some checks failed
Build and Release Electron App (electron-builder) / Compile (Typecheck + Vite Build) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (macos-latest-arm64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (ubuntu-24.04-arm-arm64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (windows-11-arm-arm64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (macos-latest-x64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (ubuntu-latest-x64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (windows-latest-x64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Create GitHub Release (push) Has been cancelled
Some checks failed
Build and Release Electron App (electron-builder) / Compile (Typecheck + Vite Build) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (macos-latest-arm64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (ubuntu-24.04-arm-arm64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (windows-11-arm-arm64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (macos-latest-x64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (ubuntu-latest-x64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Package (windows-latest-x64) (push) Has been cancelled
Build and Release Electron App (electron-builder) / Create GitHub Release (push) Has been cancelled
0.0.17
This commit is contained in:
commit
5ff536e3a5
6 changed files with 112 additions and 35 deletions
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.0.17] - 2026-05-03
|
||||
|
||||
### Added
|
||||
|
||||
- **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).
|
||||
|
||||
### Changed
|
||||
|
||||
- **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).
|
||||
- **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).
|
||||
- **Linux System Requirements.** Documentation now specifies glibc 2.28+ as a minimum requirement for Linux installations.
|
||||
|
||||
## [0.0.16] - 2026-05-02
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ Use both at the same time.
|
|||
|--|-------------|-------------|
|
||||
| **Disk** | 5 GB+ | ~500 MB |
|
||||
| **RAM** | 16 GB+ | 4 GB |
|
||||
| **OS** | macOS 12+, Windows 10+, modern Linux | Same |
|
||||
| **OS** | macOS 12+, Windows 10+, modern Linux (glibc 2.28+) | Same |
|
||||
|
||||
> [!NOTE]
|
||||
> Local models need serious RAM (7B ≈ 8 GB, 13B ≈ 16 GB). Lighter machine? Connect to a remote server instead.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "open-webui",
|
||||
"version": "0.0.16",
|
||||
"version": "0.0.17",
|
||||
"license": "AGPL-3.0",
|
||||
"description": "Open WebUI Desktop",
|
||||
"main": "./out/main/index.js",
|
||||
|
|
|
|||
|
|
@ -1272,6 +1272,61 @@ if (!gotTheLock) {
|
|||
// Malformed URL — let it through so Chromium can handle/reject it
|
||||
}
|
||||
})
|
||||
|
||||
// ── Native right-click context menu (#161) ──────────────────
|
||||
// Electron <webview> guests don't show a context menu by default,
|
||||
// which blocks right-click → Paste / Autofill / password-manager
|
||||
// integration on login pages. Build a native menu with standard
|
||||
// editing actions, spell-check suggestions, and link handling.
|
||||
contents.on('context-menu', (_event, params) => {
|
||||
const menuItems: Electron.MenuItemConstructorOptions[] = []
|
||||
|
||||
// Spell-check suggestions (if any)
|
||||
if (params.misspelledWord && params.dictionarySuggestions?.length) {
|
||||
for (const suggestion of params.dictionarySuggestions) {
|
||||
menuItems.push({
|
||||
label: suggestion,
|
||||
click: () => contents.replaceMisspelling(suggestion)
|
||||
})
|
||||
}
|
||||
menuItems.push({ type: 'separator' })
|
||||
}
|
||||
|
||||
// Link handling
|
||||
if (params.linkURL) {
|
||||
menuItems.push({
|
||||
label: 'Open Link in Browser',
|
||||
click: () => openUrl(params.linkURL)
|
||||
})
|
||||
menuItems.push({
|
||||
label: 'Copy Link',
|
||||
click: () => clipboard.writeText(params.linkURL)
|
||||
})
|
||||
menuItems.push({ type: 'separator' })
|
||||
}
|
||||
|
||||
// Editable field actions (input, textarea, contenteditable)
|
||||
if (params.isEditable) {
|
||||
menuItems.push(
|
||||
{ label: 'Undo', role: 'undo', enabled: params.editFlags.canUndo },
|
||||
{ label: 'Redo', role: 'redo', enabled: params.editFlags.canRedo },
|
||||
{ type: 'separator' },
|
||||
{ label: 'Cut', role: 'cut', enabled: params.editFlags.canCut },
|
||||
{ label: 'Copy', role: 'copy', enabled: params.editFlags.canCopy },
|
||||
{ label: 'Paste', role: 'paste', enabled: params.editFlags.canPaste },
|
||||
{ label: 'Select All', role: 'selectAll', enabled: params.editFlags.canSelectAll }
|
||||
)
|
||||
} else if (params.selectionText) {
|
||||
// Non-editable text selection
|
||||
menuItems.push(
|
||||
{ label: 'Copy', role: 'copy', enabled: params.editFlags.canCopy }
|
||||
)
|
||||
}
|
||||
|
||||
if (menuItems.length > 0) {
|
||||
Menu.buildFromTemplate(menuItems).popup()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -318,10 +318,7 @@ export const installPython = async (installationDir?: string, onStatus?: (status
|
|||
['-m', 'pip', 'install', 'uv'],
|
||||
{
|
||||
encoding: 'utf-8',
|
||||
env: {
|
||||
...process.env,
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
env: pythonEnv()
|
||||
},
|
||||
(error) => {
|
||||
if (error) reject(error)
|
||||
|
|
@ -350,6 +347,38 @@ export const getPythonPath = (installationDir?: string) => {
|
|||
return path.normalize(getPythonExecutablePath(installationDir || getPythonInstallationDir()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a process environment suitable for running the bundled Python.
|
||||
*
|
||||
* On Windows the standalone Python distribution ships its own OpenSSL DLLs
|
||||
* (`libssl-3-x64.dll`, `libcrypto-3-x64.dll`) next to `python.exe`. If a
|
||||
* different OpenSSL installation (Git for Windows, Anaconda, Strawberry Perl,
|
||||
* etc.) appears earlier on the system `PATH`, Python picks up those mismatched
|
||||
* DLLs at load-time, which causes the fatal error:
|
||||
*
|
||||
* OPENSSL_Uplink(..., 08): no OPENSSL_Applink
|
||||
*
|
||||
* To prevent this we prepend the Python installation directory to `PATH` so
|
||||
* Windows finds the correct DLLs first. On non-Windows platforms this is a
|
||||
* harmless no-op.
|
||||
*
|
||||
* Any additional env overrides (e.g. `configEnvVars`) can be spread after
|
||||
* calling this helper.
|
||||
*/
|
||||
const pythonEnv = (extra: Record<string, string> = {}): Record<string, string> => {
|
||||
const base: Record<string, string> = { ...process.env }
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// python.exe lives at the root of the installation directory on Windows
|
||||
const pythonDir = getPythonInstallationDir()
|
||||
const currentPath = process.env['PATH'] || process.env['Path'] || ''
|
||||
base['PATH'] = `${pythonDir};${currentPath}`
|
||||
base['PYTHONIOENCODING'] = 'utf-8'
|
||||
}
|
||||
|
||||
return { ...base, ...extra }
|
||||
}
|
||||
|
||||
export const isPythonInstalled = (installationDir?: string) => {
|
||||
const pythonPath = getPythonPath(installationDir)
|
||||
if (!fs.existsSync(pythonPath)) {
|
||||
|
|
@ -358,10 +387,7 @@ export const isPythonInstalled = (installationDir?: string) => {
|
|||
try {
|
||||
const pythonVersion = execFileSync(pythonPath, ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
env: {
|
||||
...process.env,
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
env: pythonEnv()
|
||||
})
|
||||
log.info('Installed Python Version:', pythonVersion.trim())
|
||||
return true
|
||||
|
|
@ -375,10 +401,7 @@ export const isUvInstalled = (installationDir?: string) => {
|
|||
try {
|
||||
const result = execFileSync(pythonPath, ['-m', 'uv', '--version'], {
|
||||
encoding: 'utf-8',
|
||||
env: {
|
||||
...process.env,
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
env: pythonEnv()
|
||||
})
|
||||
log.info('Installed uv Version:', result.trim())
|
||||
return true
|
||||
|
|
@ -428,10 +451,7 @@ export const installPackage = (packageName: string, version?: string, onStatus?:
|
|||
...(version ? [`${packageName}==${version}`] : [packageName, '-U'])
|
||||
],
|
||||
{
|
||||
env: {
|
||||
...process.env,
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
env: pythonEnv()
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -486,10 +506,7 @@ export const isPackageInstalled = (packageName: string): boolean => {
|
|||
try {
|
||||
const info = execFileSync(pythonPath, ['-m', 'uv', 'pip', 'show', packageName], {
|
||||
encoding: 'utf-8',
|
||||
env: {
|
||||
...process.env,
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
env: pythonEnv()
|
||||
})
|
||||
return info.includes(`Name: ${packageName}`)
|
||||
} catch {
|
||||
|
|
@ -503,10 +520,7 @@ export const getPackageVersion = (packageName: string): string | null => {
|
|||
try {
|
||||
const info = execFileSync(pythonPath, ['-m', 'uv', 'pip', 'show', packageName], {
|
||||
encoding: 'utf-8',
|
||||
env: {
|
||||
...process.env,
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
env: pythonEnv()
|
||||
})
|
||||
const match = info.match(/^Version:\s*(.+)$/m)
|
||||
return match ? match[1].trim() : null
|
||||
|
|
@ -521,10 +535,7 @@ export const uninstallPackage = (packageName: string): boolean => {
|
|||
try {
|
||||
execFileSync(pythonPath, ['-m', 'uv', 'pip', 'uninstall', packageName], {
|
||||
encoding: 'utf-8',
|
||||
env: {
|
||||
...process.env,
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
env: pythonEnv()
|
||||
})
|
||||
log.info(`Uninstalled package: ${packageName}`)
|
||||
return true
|
||||
|
|
@ -588,14 +599,12 @@ export const startServer = async (
|
|||
name: 'xterm-256color',
|
||||
cols: 200,
|
||||
rows: 50,
|
||||
env: {
|
||||
...process.env,
|
||||
env: pythonEnv({
|
||||
...(configEnvVars ?? {}),
|
||||
DATA_DIR: dataDir,
|
||||
WEBUI_SECRET_KEY: secretKey,
|
||||
PYTHONUNBUFFERED: '1',
|
||||
...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
|
||||
}
|
||||
PYTHONUNBUFFERED: '1'
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@
|
|||
style="display: {view === 'connected' && activeConnectionId === connId ? 'flex' : 'none'}"
|
||||
partition="persist:connection-{connId}"
|
||||
preload={contentPreloadPath}
|
||||
allowpopups
|
||||
></webview>
|
||||
{/each}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue