mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-08 03:08:02 +00:00
commit
2a960a59fe
10 changed files with 88 additions and 12 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
4
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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...": "",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue