Compare commits

..

31 Commits

Author SHA1 Message Date
Tim Baek 7104f214a8 Merge pull request #184 from open-webui/main
refac
2026-05-06 09:41:26 -04:00
Timothy Jaeryang Baek 601137c5de fix: replace --in-process-gpu with SwiftShader to fix blank webviews on Linux
The --in-process-gpu flag broke <webview> guest compositing entirely,
leaving connection views blank on all Linux configurations. SwiftShader
(--use-gl=angle --use-angle=swiftshader) keeps the GPU process
out-of-process (required for webview compositing) while using software
rendering to avoid the driver-level /dev/shm crashes that originally
motivated the in-process flag.
2026-05-06 22:41:00 +09:00
Timothy Jaeryang Baek a097a83c46 refac 2026-05-06 22:33:38 +09:00
Timothy Jaeryang Baek f8c20275cd refactor: decouple local server from connections array
The local Open WebUI server is a singleton — it's either installed or not.
Previously it was modeled as a type:'local' entry in the connections[]
config array, which broke when installing from Settings (the entry was
only created during the Get Started flow).

Now:
- connections[] is remote-only
- Local server is implicit when open-webui package is installed
- 'local' is a virtual connection ID, synthesized on the fly
- Main process: add getDefaultConnection/buildLocalConnection/resolveConnectionUrl
  helpers, replacing ~70 lines of duplicated config lookup across 5 handlers
- Renderer: localConn derived from localInstalled state, not connections store
- Push-based reactivity: main process emits connections:changed events
- Tray: virtual local entry when package is installed
- Migration: strip legacy type:'local' entries from config on startup
2026-05-06 22:09:20 +09:00
Tim Baek 4f9d09a08a Merge pull request #183 from open-webui/main
0.0.19
2026-05-06 08:19:22 -04:00
Tim Baek 5f372d0ae7 Merge pull request #181 from open-webui/main
fix: store HF models directly under models/ for llama-server discovery
2026-05-04 11:22:53 -04:00
Tim Baek 5ff536e3a5 Merge pull request #172 from open-webui/main
0.0.17
2026-05-02 11:43:04 -04:00
Tim Baek c0e463b191 Merge pull request #169 from open-webui/main
0.0.16
2026-05-02 06:05:09 -04:00
Tim Baek f646560df9 Merge pull request #160 from open-webui/main
0.0.15
2026-04-28 01:57:59 -04:00
Tim Baek 80e366a039 Merge pull request #159 from open-webui/main
0.0.14
2026-04-28 00:20:50 -04:00
Tim Baek 53df922d20 Merge pull request #151 from open-webui/main
0.0.12
2026-04-27 01:33:28 -04:00
Tim Baek 5316111679 Merge pull request #150 from open-webui/main
0.0.13
2026-04-24 11:30:09 -04:00
Tim Baek 3389039e08 Merge pull request #149 from open-webui/main
0.0.11
2026-04-24 11:03:14 -04:00
Tim Baek 1b4b9fba19 Merge pull request #148 from open-webui/main
0.0.10
2026-04-24 09:18:34 -04:00
Tim Baek 531bca9d02 Merge pull request #105 from open-webui/main
0.0.9
2026-04-20 15:58:51 +09:00
Tim Baek 60f5e922ba Merge pull request #97 from open-webui/main
refac
2026-04-11 15:21:35 -06:00
Tim Baek c85533d44d Merge pull request #96 from open-webui/main
0.0.8
2026-04-11 15:18:58 -06:00
Tim Baek 228cf1a14f Merge pull request #93 from open-webui/main
fix: macOS auto-update zip artifact naming (0.0.7)
2026-04-11 08:07:28 -07:00
Tim Baek 6255240d51 Merge pull request #92 from open-webui/main
0.0.6
2026-04-10 10:27:58 -07:00
Tim Baek 1c77c98474 Merge pull request #87 from open-webui/main
refac
2026-04-07 03:34:30 +09:00
Tim Baek 7a8e815f06 Merge pull request #86 from open-webui/main
refac
2026-04-07 03:08:02 +09:00
Tim Baek 313c48f779 Merge pull request #85 from open-webui/main
refac
2026-04-07 02:56:39 +09:00
Tim Baek 8037721480 Merge pull request #83 from open-webui/main
refac
2026-04-07 02:31:34 +09:00
Tim Baek a9d467e130 Merge pull request #82 from open-webui/main
fix: release
2026-04-07 02:16:04 +09:00
Tim Baek 3a203e07b1 Merge pull request #81 from open-webui/main
fix: release
2026-04-07 01:59:45 +09:00
Tim Baek f64c46efca Merge pull request #80 from open-webui/main
v0.0.3: fix spotlight focus after page interaction, fix ?q= query pas…
2026-04-07 01:44:18 +09:00
Tim Baek a2306585f8 Merge pull request #79 from open-webui/main
0.0.2
2026-04-07 01:33:20 +09:00
Tim Baek 32d0df2b87 Merge pull request #74 from open-webui/main
refac
2026-04-01 02:48:19 +04:00
Tim Baek 2fdf001191 Merge pull request #69 from open-webui/main
refac
2026-03-23 07:39:48 +04:00
Tim Baek 24e9e5ded2 Merge pull request #68 from open-webui/main
refac
2026-03-23 07:29:53 +04:00
Tim Baek 544656cef8 Merge pull request #67 from open-webui/main
refac
2026-03-23 07:28:11 +04:00
9 changed files with 186 additions and 153 deletions
+6
View File
@@ -5,6 +5,12 @@ 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.20] - 2026-05-07
### Fixed
- **Blank Webview on Linux.** Replaced the `--in-process-gpu` Chromium flag with SwiftShader software rendering (`--use-gl=angle --use-angle=swiftshader`). The in-process GPU flag broke `<webview>` guest compositing entirely, leaving connection views blank on all Linux configurations. SwiftShader keeps the GPU process out-of-process (required for webview compositing) while avoiding driver-level crashes (#178).
## [0.0.19] - 2026-05-06
### Fixed
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "open-webui",
"version": "0.0.19",
"version": "0.0.20",
"license": "AGPL-3.0",
"description": "Open WebUI Desktop",
"main": "./out/main/index.js",
+144 -106
View File
@@ -106,25 +106,24 @@ if (process.platform === 'linux') {
// to work (the portal is enabled by default in Chromium 134+ / Electron 33+).
app.commandLine.appendSwitch('ozone-platform-hint', 'auto')
// Run the GPU service in-process instead of in a separate sandboxed
// process. The out-of-process GPU crashes on Ubuntu 24.04+, certain
// Wayland compositors, and AppArmor-restricted environments because of
// shared-memory allocation failures in /dev/shm or /tmp (#119, #157).
// Force software GL rendering via SwiftShader. The out-of-process GPU
// crashes on Ubuntu 24.04+, certain Wayland compositors, and AppArmor-
// restricted environments due to shared-memory allocation failures in
// /dev/shm or /tmp (#119, #157).
//
// Previous attempts:
// --disable-gpu-compositing → GPU process still spawns & crashes.
// --disable-gpu → fixes crashes but kills the display
// compositor, so <webview> guest surfaces
// are never painted (gray rectangle #178).
// --disable-gpu kills the display compositor so <webview> guest surfaces
// are never painted (#178). --in-process-gpu breaks <webview> guest
// compositing entirely (blank webviews on all Linux).
//
// --in-process-gpu moves the GPU thread into the browser process, which
// sidesteps the cross-process shared-memory IPC entirely while keeping
// the display compositor alive so webview content renders normally.
app.commandLine.appendSwitch('in-process-gpu')
// SwiftShader keeps the GPU process out-of-process (required for
// <webview> compositing) while using software rendering to avoid
// driver-level crashes.
app.commandLine.appendSwitch('use-gl', 'angle')
app.commandLine.appendSwitch('use-angle', 'swiftshader')
// Disable the GPU sandbox — it is the sandbox setup that triggers the
// shared-memory failures. With --in-process-gpu the GPU thread lives
// in the browser process which is already un-sandboxed (--no-sandbox).
// Disable the GPU sandbox — the sandbox setup triggers shared-memory
// allocation failures in /dev/shm. The browser process is already
// un-sandboxed (--no-sandbox above).
app.commandLine.appendSwitch('disable-gpu-sandbox')
}
@@ -507,8 +506,8 @@ async function toggleVoiceInput(): Promise<void> {
// Pre-flight: check a connection is configured
try {
const config = await getConfig()
if (!config.defaultConnectionId || config.connections.length === 0) {
const conn = await getDefaultConnection()
if (!conn) {
log.warn('Voice input: no connection configured')
new Notification({
title: 'Voice Input',
@@ -516,15 +515,6 @@ async function toggleVoiceInput(): Promise<void> {
}).show()
return
}
const conn = config.connections.find((c) => c.id === config.defaultConnectionId)
if (!conn) {
log.warn('Voice input: default connection not found')
new Notification({
title: 'Voice Input',
body: 'Default connection not found. Check your connection settings.'
}).show()
return
}
} catch (err: any) {
log.warn('Voice input: config check failed:', err)
}
@@ -554,8 +544,8 @@ async function toggleVoiceInput(): Promise<void> {
async function toggleCall(): Promise<void> {
// Pre-flight: check a connection is configured
try {
const config = await getConfig()
if (!config.defaultConnectionId || config.connections.length === 0) {
const conn = await getDefaultConnection()
if (!conn) {
log.warn('Call: no connection configured')
new Notification({
title: 'Call',
@@ -563,24 +553,8 @@ async function toggleCall(): Promise<void> {
}).show()
return
}
const conn = config.connections.find((c) => c.id === config.defaultConnectionId)
if (!conn) {
log.warn('Call: default connection not found')
new Notification({
title: 'Call',
body: 'Default connection not found. Check your connection settings.'
}).show()
return
}
let url = conn.url
if (conn.type === 'local' && SERVER_URL) {
url = SERVER_URL
}
if (url.startsWith('http://0.0.0.0')) {
url = url.replace('http://0.0.0.0', 'http://localhost')
}
const url = resolveConnectionUrl(conn)
sendToRenderer('call', { connectionId: conn.id, url })
if (mainWindow && !mainWindow.isDestroyed()) {
@@ -796,7 +770,8 @@ function createContentWindow(url: string, connectionId: string): BrowserWindow {
const updateTray = () => {
if (!tray || !CONFIG) return
const connectionItems = (CONFIG.connections || []).map((conn) => ({
// Remote connections from config
const remoteItems = (CONFIG.connections || []).map((conn) => ({
label: `${conn.id === CONFIG.defaultConnectionId ? '★ ' : ''}${conn.name}`,
sublabel: conn.url,
click: async () => {
@@ -805,6 +780,20 @@ const updateTray = () => {
}
}))
// Virtual local connection (when package is installed)
const localItem = isPackageInstalled('open-webui')
? [{
label: `${CONFIG.defaultConnectionId === 'local' ? '★ ' : ''}Open WebUI (Local)`,
sublabel: SERVER_URL || `http://127.0.0.1:${CONFIG.localServer?.port ?? 8080}`,
click: async () => {
const result = await connectTo(buildLocalConnection())
if (result) sendToRenderer('connection:open', result)
}
}]
: []
const allItems = [...localItem, ...remoteItems]
const trayMenuTemplate = [
{
label: 'Show Open WebUI',
@@ -814,10 +803,10 @@ const updateTray = () => {
}
},
{ type: 'separator' },
...(connectionItems.length > 0
...(allItems.length > 0
? [
{ label: 'Connections', enabled: false },
...connectionItems,
...allItems,
{ type: 'separator' }
]
: []),
@@ -849,6 +838,38 @@ const updateTray = () => {
// ─── Connection Management ──────────────────────────────
// Build a virtual local connection object from current config.
// The local server is never stored in the connections array — it's
// implicit when the open-webui package is installed.
const buildLocalConnection = (): Connection => {
const port = CONFIG?.localServer?.port ?? 8080
return {
id: 'local',
name: 'Open WebUI',
type: 'local',
url: SERVER_URL || `http://127.0.0.1:${port}`
}
}
// Resolve the default connection. 'local' is a virtual ID that
// synthesises a Connection on the fly; everything else is looked
// up in the persisted connections array (remote only).
const getDefaultConnection = async (): Promise<Connection | null> => {
const config = await getConfig()
if (!config.defaultConnectionId) return null
if (config.defaultConnectionId === 'local') return buildLocalConnection()
return config.connections.find((c) => c.id === config.defaultConnectionId) ?? null
}
// Resolve the URL for a connection, preferring the live SERVER_URL
// for local connections and normalising 0.0.0.0 to localhost.
const resolveConnectionUrl = (conn: Connection): string => {
let url = conn.url
if (conn.type === 'local' && SERVER_URL) url = SERVER_URL
if (url.startsWith('http://0.0.0.0')) url = url.replace('http://0.0.0.0', 'http://localhost')
return url
}
const connectTo = async (connection: Connection) => {
let url = connection.url
@@ -902,6 +923,27 @@ const startServerHandler = async (): Promise<boolean> => {
try {
CONFIG = await getConfig()
// Auto-update the open-webui pip package to latest before starting.
// Only when autoUpdate is enabled (default) and no version pin is set.
const autoUpdate = CONFIG?.localServer?.autoUpdate !== false
const versionPin = CONFIG?.localServer?.version
if (autoUpdate && !versionPin && isPackageInstalled('open-webui')) {
try {
log.info('[server] Auto-updating open-webui package to latest…')
sendToRenderer('status:install', 'Updating Open WebUI…')
await installPackage('open-webui', undefined, (status: string) => {
sendToRenderer('status:install', status)
})
sendToRenderer('status:install', '')
log.info('[server] Auto-update complete')
} catch (e) {
// Non-fatal — start the existing version if upgrade fails
log.warn('[server] Auto-update failed, starting existing version:', e)
sendToRenderer('status:install', '')
}
}
const { url, pid } = await startServer(
CONFIG?.localServer?.serveOnLocalNetwork ?? false,
CONFIG?.localServer?.port ?? null
@@ -1430,6 +1472,18 @@ if (!gotTheLock) {
log.warn('open-terminal install failed (non-fatal):', e)
)
sendToRenderer('status:package', true)
// Notify renderer of install state change
sendToRenderer('packages:changed', {
'open-webui': isPackageInstalled('open-webui')
})
// Auto-set local as default if no default configured
const cfg = await getConfig()
if (!cfg.defaultConnectionId) {
cfg.defaultConnectionId = 'local'
await setConfig(cfg)
CONFIG = cfg
}
updateTray()
return true
} catch (error) {
sendToRenderer('status:package', false)
@@ -1460,7 +1514,7 @@ if (!gotTheLock) {
reachable: SERVER_REACHABLE
}))
// Connections
// Connections (remote only — local is virtual)
ipcMain.handle('connections:list', async () => {
const config = await getConfig()
return config.connections
@@ -1475,6 +1529,7 @@ if (!gotTheLock) {
await setConfig(config)
CONFIG = config
updateTray()
sendToRenderer('connections:changed', config.connections)
return config.connections
})
@@ -1482,11 +1537,12 @@ if (!gotTheLock) {
const config = await getConfig()
config.connections = config.connections.filter((c) => c.id !== id)
if (config.defaultConnectionId === id) {
config.defaultConnectionId = config.connections[0]?.id || null
config.defaultConnectionId = config.connections[0]?.id || 'local'
}
await setConfig(config)
CONFIG = config
updateTray()
sendToRenderer('connections:changed', config.connections)
return config.connections
})
@@ -1498,6 +1554,7 @@ if (!gotTheLock) {
await setConfig(config)
CONFIG = config
updateTray()
sendToRenderer('connections:changed', config.connections)
}
return config.connections
})
@@ -1511,6 +1568,10 @@ if (!gotTheLock) {
})
ipcMain.handle('connections:connect', async (_event, id: string) => {
// 'local' is a virtual connection — synthesize it
if (id === 'local') {
return await connectTo(buildLocalConnection())
}
const config = await getConfig()
const conn = config.connections.find((c) => c.id === id)
if (conn) {
@@ -1551,26 +1612,14 @@ if (!gotTheLock) {
// Spotlight
ipcMain.handle('spotlight:submit', async (_event, query: string, images?: string[]) => {
const config = await getConfig()
if (!config.defaultConnectionId || config.connections.length === 0) {
mainWindow?.show()
mainWindow?.focus()
return
}
const conn = config.connections.find((c) => c.id === config.defaultConnectionId)
const conn = await getDefaultConnection()
if (!conn) {
mainWindow?.show()
mainWindow?.focus()
return
}
let url = conn.url
if (conn.type === 'local' && SERVER_URL) {
url = SERVER_URL
}
if (url.startsWith('http://0.0.0.0')) {
url = url.replace('http://0.0.0.0', 'http://localhost')
}
const url = resolveConnectionUrl(conn)
// Build files payload from screenshot images
const files = images?.map((dataUrl, i) => ({
@@ -1697,20 +1746,10 @@ if (!gotTheLock) {
// Transcribe audio via the connected server's STT endpoint
ipcMain.handle('voiceInput:transcribe', async (_event, audioBuffer: ArrayBuffer, rendererToken?: string) => {
try {
const config = await getConfig()
if (!config.defaultConnectionId || config.connections.length === 0) {
throw new Error('No connection configured. Set up a connection in Settings first.')
}
const conn = config.connections.find((c) => c.id === config.defaultConnectionId)
if (!conn) throw new Error('Default connection not found. Check your connection settings.')
const conn = await getDefaultConnection()
if (!conn) throw new Error('No connection configured. Set up a connection in Settings first.')
let url = conn.url
if (conn.type === 'local' && SERVER_URL) {
url = SERVER_URL
}
if (url.startsWith('http://0.0.0.0')) {
url = url.replace('http://0.0.0.0', 'http://localhost')
}
const url = resolveConnectionUrl(conn)
// Use stored auth token (relayed from webview), fall back to renderer-provided or contentWindow
let token = AUTH_TOKEN || rendererToken || ''
@@ -1795,27 +1834,14 @@ if (!gotTheLock) {
if (!text?.trim()) return
// Deliver text through the same path as Spotlight
const config = await getConfig()
if (!config.defaultConnectionId || config.connections.length === 0) {
mainWindow?.show()
mainWindow?.focus()
return
}
const conn = config.connections.find((c) => c.id === config.defaultConnectionId)
const conn = await getDefaultConnection()
if (!conn) {
mainWindow?.show()
mainWindow?.focus()
return
}
let url = conn.url
if (conn.type === 'local' && SERVER_URL) {
url = SERVER_URL
}
if (url.startsWith('http://0.0.0.0')) {
url = url.replace('http://0.0.0.0', 'http://localhost')
}
const url = resolveConnectionUrl(conn)
sendToRenderer('query', { query: text.trim(), connectionId: conn.id, url })
if (mainWindow && !mainWindow.isDestroyed()) {
@@ -1924,7 +1950,8 @@ if (!gotTheLock) {
if (result.url) {
sendToRenderer('connections:openai', {
action: 'add',
url: `${result.url}/v1`
url: `${result.url}/v1`,
config: { provider: 'llama.cpp', connection_type: 'local' }
})
// Refresh model list after backend registers the endpoint
setTimeout(() => sendToRenderer('models:refresh'), 1000)
@@ -2029,7 +2056,13 @@ if (!gotTheLock) {
ipcMain.handle('package:version', (_event, packageName: string) => getPackageVersion(packageName))
ipcMain.handle('package:uninstall', async (_event, packageName: string) => {
return uninstallPackage(packageName)
const result = uninstallPackage(packageName)
// Notify renderer of install state change
sendToRenderer('packages:changed', {
'open-webui': isPackageInstalled('open-webui')
})
updateTray()
return result
})
ipcMain.handle('dialog:selectFolder', async () => {
@@ -2146,18 +2179,23 @@ if (!gotTheLock) {
}
}
// Check if already configured, auto-connect to default
if (CONFIG.defaultConnectionId && CONFIG.connections.length > 0) {
const defaultConn = CONFIG.connections.find(
(c) => c.id === CONFIG.defaultConnectionId
)
if (defaultConn) {
createMainWindow()
const result = await connectTo(defaultConn)
if (result) sendToRenderer('connection:open', result)
} else {
createMainWindow()
// Migrate legacy local connection entries out of the connections array
if (CONFIG.connections.some((c) => c.type === 'local')) {
CONFIG.connections = CONFIG.connections.filter((c) => c.type !== 'local')
// Preserve 'local' as default if it was the default
if (!CONFIG.defaultConnectionId || CONFIG.defaultConnectionId === 'local') {
CONFIG.defaultConnectionId = 'local'
}
await setConfig(CONFIG)
log.info('Migrated legacy local connection entry from connections array')
}
// Check if already configured, auto-connect to default
const defaultConn = await getDefaultConnection()
if (defaultConn) {
createMainWindow()
const result = await connectTo(defaultConn)
if (result) sendToRenderer('connection:open', result)
} else {
createMainWindow()
}
@@ -50,9 +50,11 @@
const serverReachable = $derived($serverInfo?.reachable)
const isInitializing = $derived($appState === 'initializing')
const hasLocal = $derived(($connections ?? []).some((c) => c.type === 'local'))
const localConn = $derived(($connections ?? []).find((c) => c.type === 'local'))
const remoteConnections = $derived(($connections ?? []).filter((c) => c.type !== 'local'))
const localConn = $derived(localInstalled
? { id: 'local', name: 'Open WebUI', type: 'local' as const, url: `http://127.0.0.1:${$config?.localServer?.port ?? 8080}` }
: null
)
const remoteConnections = $derived($connections ?? [])
// Open Terminal state
let openTerminalStatus = $state<string | null>(null)
@@ -110,14 +112,7 @@
const info = await window.electronAPI.getServerInfo()
installStatus = $i18n.t('main.install.settingUpConnection')
await window.electronAPI.addConnection({
id: 'local',
name: 'Local',
type: 'local',
url: info?.url || 'http://127.0.0.1:8080'
})
await window.electronAPI.setDefaultConnection('local')
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
// Wait for server to actually be reachable before showing connected view
@@ -141,7 +136,6 @@
// Now connect — the server is ready
installStatus = ''
localInstalled = true
connect('local')
installPhase = 'idle'
} catch (e: any) {
@@ -178,7 +172,6 @@
type: 'remote',
url: u
})
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
url = ''
error = ''
@@ -212,13 +205,10 @@
return
}
const conn = ($connections ?? []).find((c) => c.id === id)
if (!conn) return
activeConnectionId = id
if (conn.type === 'local') {
// Local needs server start — use IPC
if (id === 'local') {
// Local needs server start — use IPC (no renderer-side conn needed)
connectingId = id
view = 'welcome'
window.electronAPI.connectTo(id).then((result: any) => {
@@ -240,6 +230,8 @@
}
})
} else {
const conn = ($connections ?? []).find((c) => c.id === id)
if (!conn) return
// Remote — open immediately, no IPC needed
connectingId = ''
openConnections.set(id, conn.url)
@@ -257,7 +249,6 @@
const remove = async (id: string) => {
await window.electronAPI.removeConnection(id)
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
if (activeConnectionId === id) {
disconnect()
@@ -266,11 +257,15 @@
openConnections = new Map(openConnections)
}
// Sync active connection info to parent
$effect(() => {
const conn = ($connections ?? []).find((c) => c.id === activeConnectionId)
activeConnectionName = conn?.name ?? ''
isLocalConnection = conn?.type === 'local'
if (activeConnectionId === 'local') {
activeConnectionName = localConn?.name ?? 'Open WebUI'
isLocalConnection = true
} else {
const conn = ($connections ?? []).find((c) => c.id === activeConnectionId)
activeConnectionName = conn?.name ?? ''
isLocalConnection = false
}
})
// React to showingLogs from parent — open the server log panel
@@ -439,6 +434,14 @@
if (data.type === 'status:llamacpp-setup') { llamaCppSetupStatus = data.data ?? ''; return }
if (data.type === 'llamacpp:ready') { llamaCppInfo = data.data; llamaCppStatus = 'started'; llamaCppSetupStatus = ''; return }
if (data.type === 'status:install') { installStatus = data.data ?? ''; return }
if (data.type === 'packages:changed') {
localInstalled = !!data.data?.['open-webui']
return
}
if (data.type === 'connections:changed') {
connections.set(data.data ?? [])
return
}
// ── Everything else → broadcast to all webviews ───
sendToWebview(data)
@@ -543,7 +546,6 @@
{onOpenSettings}
onRename={async (id, name) => {
await window.electronAPI.updateConnection(id, { name })
connections.set(await window.electronAPI.getConnections())
}}
onRemove={remove}
{openGithub}
@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte'
import { fade, fly } from 'svelte/transition'
import { connections, config, serverInfo, appState } from '../../../stores'
import { config, serverInfo, appState } from '../../../stores'
import i18n from '../../../i18n'
import LocalInstall from '../../Setup/LocalInstall.svelte'
import GetStartedModal from './GetStartedModal.svelte'
@@ -80,7 +80,7 @@
// Server is starting up (local)
const serverStarting = $derived(
localConn && localInstalled && (
localInstalled && (
$serverInfo?.status === 'starting' ||
($serverInfo?.status === 'running' && !$serverInfo?.reachable)
)
@@ -94,7 +94,7 @@
const isLoading = $derived(
connectingId !== '' ||
(serverStarting && activeConnectionId === localConn?.id) ||
(serverStarting && activeConnectionId === 'local') ||
(view === 'connected' && !activeWebviewError && webviewLoading.get(activeConnectionId) === true)
)
@@ -389,7 +389,7 @@
<div class="flex-1 flex items-center justify-center px-6 relative overflow-hidden">
{#if view === 'welcome'}
{#if remoteConnections.length > 0 || (localConn && localInstalled)}
{#if remoteConnections.length > 0 || localInstalled}
<div class="text-center max-w-[320px]" in:fade={{ duration: 200 }}>
<div class="text-lg opacity-80 mb-1.5">{$i18n.t('app.name')}</div>
<div class="text-[12px] opacity-30 mb-6">
@@ -487,7 +487,6 @@
autoStart={autoInstall}
onBack={() => { autoInstall = false; onSetView('welcome') }}
onComplete={async () => {
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
onSetView('welcome')
}}
@@ -4,7 +4,6 @@
const remove = async (id: string) => {
await window.electronAPI.removeConnection(id)
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
}
</script>
@@ -34,7 +34,6 @@
type: 'remote',
url: u
})
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
url = ''; name = ''; view = 'list'
} catch { error = $i18n.t('setup.connectionManager.failed') }
@@ -48,10 +47,8 @@
}
const remove = async (id: string) => {
await window.electronAPI.removeConnection(id)
const conns = await window.electronAPI.getConnections()
connections.set(conns)
config.set(await window.electronAPI.getConfig())
if (conns.length === 0) appState.set('setup')
if (($connections ?? []).length === 0) appState.set('setup')
}
</script>
@@ -1,7 +1,7 @@
<script lang="ts">
import { fade, fly } from 'svelte/transition'
import { onMount } from 'svelte'
import { connections, config, serverInfo } from '../../stores'
import { config, serverInfo } from '../../stores'
import i18n from '../../i18n'
import logoImage from '../../assets/images/splash.png'
@@ -33,14 +33,7 @@
await window.electronAPI.startServer()
const info = await window.electronAPI.getServerInfo()
await window.electronAPI.addConnection({
id: 'local',
name: 'Local',
type: 'local',
url: info?.url || 'http://127.0.0.1:8080'
})
await window.electronAPI.setDefaultConnection('local')
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
phase = 'done'
@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte'
import { fly, fade } from 'svelte/transition'
import { appState, connections, config } from '../../stores'
import { appState, config } from '../../stores'
import i18n from '../../i18n'
import LocalInstall from './LocalInstall.svelte'
@@ -30,16 +30,15 @@
try {
const valid = await window.electronAPI.validateUrl(u)
if (!valid) { error = $i18n.t('setup.couldNotReachServer'); connecting = false; return }
const connId = crypto.randomUUID()
await window.electronAPI.addConnection({
id: crypto.randomUUID(),
id: connId,
name: new URL(u).hostname,
type: 'remote',
url: u
})
connections.set(await window.electronAPI.getConnections())
config.set(await window.electronAPI.getConfig())
const conns = await window.electronAPI.getConnections()
await window.electronAPI.connectTo(conns[conns.length - 1].id)
await window.electronAPI.connectTo(connId)
appState.set('ready')
} catch {
error = $i18n.t('setup.connectionFailed')