Merge pull request #29309 from open-webui/dev

0.11.3
This commit is contained in:
Tim Baek 2026-08-31 10:55:42 -04:00 • committed by GitHub
commit 2a960a59fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 88 additions and 12 deletions

View file

@ -5,6 +5,21 @@ 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.11.3] - 2026-08-31
### Added
- ♿ **Accessibility mode reaches the menus.** Accessibility mode now marks the menu entry you are pointing at and the model already chosen with a stronger background, across the dropdown menus, their submenus, and the model picker together with its filter and compare controls, so those cues carry the contrast the accessibility guidelines ask for in both themes. [Commit](https://github.com/open-webui/open-webui/commit/a6f9751401589ee73208295b6f6a7f6eae9c1b44), [Commit](https://github.com/open-webui/open-webui/commit/471b5cbbb16c3996c32e68808dde6f8898f64ecd)
- 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security.
- 🌐 **Translation updates.** Translations for Indonesian were enhanced and expanded.
### Fixed
- 💥 **Chat branches stay connected after reloads.** A reply saved under an earlier message now stays listed under that message, so branch arrows, exports, reloads, and later edits keep the whole conversation in view, and chats already saved with that link missing are repaired when opened. [#29299](https://github.com/open-webui/open-webui/issues/29299)
- 🧱 **Upgrades fail clearly instead of starting half updated.** A failed database upgrade now stops at the migration error that caused it, instead of starting anyway and reporting a missing table or column such as 'chat.timer_at' later, which is the upgrade failure seen after moving from 0.11.0, 0.11.1, or 0.11.2. [#29280](https://github.com/open-webui/open-webui/issues/29280)
- 🔤 **Custom interface fonts reach more of the app.** The font chosen in interface settings now applies to dropdowns and other interface text that previously fell back to the standard font. [Commit](https://github.com/open-webui/open-webui/commit/1457000ba66547b24bd98012aa35ac16fd4bc696)
- 🔌 **Disconnect OAuth only where there is OAuth.** The disconnect control on a tool server reached over MCP now appears only where that server signs in through OAuth and an account is connected, rather than on servers that use no sign-in at all. [#29296](https://github.com/open-webui/open-webui/issues/29296)
## [0.11.2] - 2026-08-31
### Added

View file

@ -74,6 +74,7 @@ def run_migrations():
command.upgrade(alembic_cfg, 'head')
except Exception as e:
log.exception(f'Error running migrations: {e}')
raise
if ENABLE_DB_MIGRATIONS:

View file

@ -8,7 +8,6 @@ from open_webui.constants import ERROR_MESSAGES
from open_webui.models.access_grants import AccessGrantModel, AccessGrants
from open_webui.models.groups import Groups
from open_webui.models.users import User, UserModel, UserResponse
from open_webui.utils.automations import rrule_interval_seconds
from pydantic import BaseModel, ConfigDict, Field, field_validator
from sqlalchemy import (
JSON,
@ -198,6 +197,8 @@ class CalendarEventForm(BaseModel):
@classmethod
def reject_sub_daily_rrule(cls, value: Optional[str]) -> Optional[str]:
if value:
from open_webui.utils.automations import rrule_interval_seconds
try:
interval = rrule_interval_seconds(value)
except ValueError:
@ -228,6 +229,8 @@ class CalendarEventUpdateForm(BaseModel):
@classmethod
def reject_sub_daily_rrule(cls, value: Optional[str]) -> Optional[str]:
if value:
from open_webui.utils.automations import rrule_interval_seconds
try:
interval = rrule_interval_seconds(value)
except ValueError:

View file

@ -456,6 +456,23 @@ class ChatTable:
message_id = next_id
return message_id
@staticmethod
def _add_child_id_to_parent(messages: dict, parent_id: str | None, child_id: str) -> bool:
parent = messages.get(parent_id) if parent_id else None
if not isinstance(parent, dict):
return False
child_ids = parent.get('childrenIds')
if not isinstance(child_ids, list):
child_ids = []
parent['childrenIds'] = child_ids
if child_id in child_ids:
return False
child_ids.append(child_id)
return True
def _repair_chat_current_id(self, chat: dict) -> bool:
history = chat.get('history')
if not isinstance(history, dict):
@ -465,6 +482,12 @@ class ChatTable:
if not isinstance(messages, dict):
return False
changed = False
for message_id, message in messages.items():
if not isinstance(message, dict):
continue
changed = self._add_child_id_to_parent(messages, message.get('parentId'), message_id) or changed
current_id = history.get('currentId')
current_message = messages.get(current_id)
output = []
@ -494,7 +517,7 @@ class ChatTable:
history['currentId'] = last_descendant_id
return True
return False
return changed
latest_leaf_id = None
latest_timestamp = -1
@ -509,7 +532,7 @@ class ChatTable:
latest_timestamp = timestamp
if not latest_leaf_id or latest_leaf_id == current_id:
return False
return changed
history['currentId'] = latest_leaf_id
return True
@ -998,6 +1021,8 @@ class ChatTable:
'timestamp': message.get('timestamp') or int(time.time()),
}
history['currentId'] = message_id
ChatTable._add_child_id_to_parent(messages, messages[message_id].get('parentId'), message_id)
return messages[message_id]
async def backfill_messages_by_chat_id(self, chat_id: str, user_id: str, messages: dict[str, dict]) -> None:

View file

@ -918,6 +918,14 @@ async def image_edits(
return data
if data.startswith('http://') or data.startswith('https://'):
parsed = urlparse(data)
if (
parsed.netloc == urlparse(str(request.base_url)).netloc
and parsed.path.startswith('/api/v1/files/')
and '/content' in parsed.path
):
return await load_url_image(parsed.path)
# Validate URL to prevent SSRF attacks against local/private networks.
# allow_redirects=False prevents redirect-based SSRF: validate_url() is
# called only on the originally-submitted URL; following 3xx redirects

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "open-webui",
"version": "0.11.2",
"version": "0.11.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "open-webui",
"version": "0.11.2",
"version": "0.11.3",
"dependencies": {
"@azure/msal-browser": "^4.5.0",
"@codemirror/lang-javascript": "^6.2.2",

View file

@ -1,6 +1,6 @@
{
"name": "open-webui",
"version": "0.11.2",
"version": "0.11.3",
"private": true,
"scripts": {
"dev": "npm run pyodide:fetch && vite dev --host",

View file

@ -524,7 +524,7 @@
</div>
</div>
{#if (tools?.[toolId]?.authenticated ?? true) && toolId.startsWith('server:mcp:')}
{#if tools?.[toolId]?.authenticated === true && toolId.startsWith('server:mcp:')}
<div class="shrink-0">
<Tooltip content={$i18n.t('Disconnect OAuth')}>
<button

View file

@ -10,18 +10,25 @@
"{{COUNT}} Available Tools": "",
"{{COUNT}} characters": "",
"{{COUNT}} extracted lines": "",
"{{count}} files_one": "{{count}} berkas",
"{{count}} files_other": "",
"{{COUNT}} files": "",
"{{count}} files selected. Only new and modified files will be uploaded. Deleted files will be removed. The folder structure will be mirrored. Continue?_one": "{{count}} berkas dipilih. Hanya berkas baru dan yang dimodifikasi yang akan diunggah. Berkas yang dihapus akan disingkirkan. Struktur folder akan disinkronkan. Lanjutkan?",
"{{count}} files selected. Only new and modified files will be uploaded. Deleted files will be removed. The folder structure will be mirrored. Continue?_other": "",
"{{count}} filters_one": "{{count}} filter",
"{{count}} filters_other": "",
"{{count}} groups_one": "{{count}} grup",
"{{count}} groups_other": "",
"{{COUNT}} hidden lines": "",
"{{COUNT}} members": "",
"{{count}} of {{total}} accessible_one": "{{count}} dari {{total}} dapat diakses",
"{{count}} of {{total}} accessible_other": "",
"{{COUNT}} Replies": "",
"{{COUNT}} Rows": "",
"{{count}} selected_one": "{{count}} dipilih",
"{{count}} selected_other": "",
"{{COUNT}} Sources": "",
"{{count}} users_one": "{{count}} pengguna",
"{{count}} users_other": "",
"{{COUNT}} words": "",
"{{COUNT}}d_time_ago": "",
@ -574,6 +581,7 @@
"Completions": "",
"Compress Images in Channels": "",
"Compress uploaded images before sending or storage.": "",
"Computing checksums ({{count}} files)_one": "Menghitung checksum ({{count}} berkas)",
"Computing checksums ({{count}} files)_other": "",
"Concurrent Requests": "Permintaan Bersamaan",
"Config": "",
@ -1123,7 +1131,9 @@
"Event title": "",
"Event updated": "",
"Events": "",
"Every {{count}} hours_one": "Setiap {{count}} jam",
"Every {{count}} hours_other": "",
"Every {{count}} minutes_one": "Setiap {{count}} menit",
"Every {{count}} minutes_other": "",
"Every minute": "",
"Exa API Key": "",
@ -2201,6 +2211,7 @@
"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative.": "",
"Reference Chats": "",
"Refresh": "",
"Refresh requested: {{count}} terminal(s)_one": "Permintaan muat ulang: {{count}} terminal",
"Refresh requested: {{count}} terminal(s)_other": "",
"Refresh Terminals": "",
"Refresh the account email from OAuth on sign-in.": "",
@ -2236,6 +2247,7 @@
"Remove Pinned Model": "",
"Remove prompt suggestion": "",
"Remove Selected Model": "",
"Removing {{count}} stale files..._one": "Menghapus {{count}} berkas usang...",
"Removing {{count}} stale files..._other": "",
"Rename": "Ganti nama",
"Renamed to {{name}}": "",
@ -2281,6 +2293,7 @@
"Retrieval": "",
"Retrieval Query Generation": "",
"Retrieved {{count}} sources": "",
"Retrieved {{count}} sources_one": "Mengambil {{count}} sumber",
"Retrieved {{count}} sources_other": "",
"Retrieved 1 source": "",
"Retry": "",
@ -2581,6 +2594,7 @@
"Start of the channel": "Awal saluran",
"Start Tag": "",
"Start the chat to use this terminal.": "",
"Starting in {{count}} minutes_one": "Mulai dalam {{count}} menit",
"Starting in {{count}} minutes_other": "",
"Starting in 1 minute": "",
"Starting kernel...": "",

View file

@ -3,6 +3,13 @@
@config '../tailwind.config.js';
@theme {
--font-sans:
var(--app-font-family, -apple-system), BlinkMacSystemFont, 'Inter', 'Vazirmatn', ui-sans-serif,
system-ui, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue',
Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-primary: var(--font-sans);
--font-secondary: var(--font-sans);
--color-gray-50: oklch(0.98 0 0);
--color-gray-100: oklch(0.94 0 0);
--color-gray-200: oklch(0.92 0 0);
@ -37,11 +44,7 @@
@layer base {
html {
font-family:
var(--app-font-family, -apple-system), BlinkMacSystemFont, 'Inter', 'Vazirmatn',
ui-sans-serif, system-ui, 'Segoe UI', Roboto, Ubuntu, Cantarell, 'Noto Sans', sans-serif,
'Helvetica Neue', Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
font-family: var(--font-sans);
}
pre {
@ -97,4 +100,11 @@
}
}
@layer utilities {
.font-primary,
.font-secondary {
font-family: var(--font-sans);
}
}
@custom-variant hover (&:hover);