mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-27 07:54:55 -06:00
@@ -5,6 +5,15 @@ 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.8.7] - 2026-03-01
|
||||
|
||||
### Fixed
|
||||
|
||||
- 🔒 **Connection access control privacy.** Tool server and terminal connections without explicit access grants are now private (admin-only) by default, fixing a bug where connections configured with no access grants were visible to all users instead of being restricted. [Commit](https://github.com/open-webui/open-webui/commit/2751a0f0b)
|
||||
- 🧠 **ChatControls memory leak.** The ChatControls panel no longer leaks event listeners, ResizeObserver instances, and media query handlers when navigating between chats, fixing memory accumulation that could degrade performance during extended use. [#22112](https://github.com/open-webui/open-webui/pull/22112)
|
||||
- 💾 **Temporary chat params preservation.** Model parameters are now correctly saved when creating a temporary chat, ensuring custom settings like temperature and top_p persist across the session. [Commit](https://github.com/open-webui/open-webui/commit/fe837d80e)
|
||||
- ⚡ **Faster artifact content updates.** Artifact content extraction during streaming is now debounced via requestAnimationFrame, reducing redundant DOM reads and improving CPU efficiency when tokens arrive faster than the browser can paint. [Commit](https://github.com/open-webui/open-webui/commit/6863ca482)
|
||||
|
||||
## [0.8.6] - 2026-03-01
|
||||
|
||||
### Added
|
||||
|
||||
@@ -163,8 +163,8 @@ def has_connection_access(
|
||||
based on ``config.access_grants`` within the connection dict.
|
||||
|
||||
- Admin with BYPASS_ADMIN_ACCESS_CONTROL → always allowed
|
||||
- Empty / missing access_grants → allowed for all users
|
||||
- Otherwise → delegates to ``has_access``
|
||||
- Missing, None, or empty access_grants → private, admin-only
|
||||
- access_grants has entries → delegates to ``has_access``
|
||||
"""
|
||||
from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL
|
||||
|
||||
@@ -175,9 +175,6 @@ def has_connection_access(
|
||||
user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user.id)}
|
||||
|
||||
access_grants = (connection.get("config") or {}).get("access_grants", [])
|
||||
if not access_grants:
|
||||
return True
|
||||
|
||||
return has_access(user.id, "read", access_grants, user_group_ids)
|
||||
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "open-webui",
|
||||
"version": "0.8.6",
|
||||
"version": "0.8.7",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "open-webui",
|
||||
"version": "0.8.6",
|
||||
"version": "0.8.7",
|
||||
"dependencies": {
|
||||
"@azure/msal-browser": "^4.5.0",
|
||||
"@codemirror/lang-javascript": "^6.2.2",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "open-webui",
|
||||
"version": "0.8.6",
|
||||
"version": "0.8.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run pyodide:fetch && vite dev --host",
|
||||
|
||||
@@ -964,7 +964,11 @@
|
||||
};
|
||||
|
||||
$: if (history) {
|
||||
getContents();
|
||||
cancelAnimationFrame(contentsRAF);
|
||||
contentsRAF = requestAnimationFrame(() => {
|
||||
getContents();
|
||||
contentsRAF = null;
|
||||
});
|
||||
} else {
|
||||
artifactContents.set([]);
|
||||
}
|
||||
@@ -1294,6 +1298,7 @@
|
||||
};
|
||||
|
||||
let scrollRAF = null;
|
||||
let contentsRAF = null;
|
||||
const scheduleScrollToBottom = () => {
|
||||
if (!scrollRAF) {
|
||||
scrollRAF = requestAnimationFrame(async () => {
|
||||
@@ -2719,6 +2724,7 @@
|
||||
id: uuidv4(),
|
||||
title: title.length > 50 ? `${title.slice(0, 50)}...` : title,
|
||||
models: selectedModels,
|
||||
params: params,
|
||||
history: history,
|
||||
messages: messages,
|
||||
timestamp: Date.now()
|
||||
|
||||
@@ -50,9 +50,8 @@
|
||||
export let files;
|
||||
export let modelId;
|
||||
|
||||
export let pane;
|
||||
export let pane: Pane | null = null;
|
||||
|
||||
let mediaQuery;
|
||||
let largeScreen = false;
|
||||
let dragged = false;
|
||||
let minSize = 0;
|
||||
@@ -172,56 +171,67 @@
|
||||
dragged = false;
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
mediaQuery = window.matchMedia('(min-width: 1024px)');
|
||||
onMount(() => {
|
||||
const mediaQuery = window.matchMedia('(min-width: 1024px)');
|
||||
mediaQuery.addEventListener('change', handleMediaQuery);
|
||||
handleMediaQuery(mediaQuery);
|
||||
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let isDestroyed = false;
|
||||
|
||||
// Wait for Svelte to render the Pane after largeScreen changed
|
||||
await tick();
|
||||
const init = async () => {
|
||||
await tick();
|
||||
|
||||
const container = document.getElementById('chat-container');
|
||||
minSize = Math.floor((350 / container.clientWidth) * 100);
|
||||
if (isDestroyed) return;
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (let entry of entries) {
|
||||
const width = entry.contentRect.width;
|
||||
minSize = Math.floor((350 / width) * 100);
|
||||
if ($showControls) {
|
||||
if (pane && pane.isExpanded() && pane.getSize() < minSize) {
|
||||
pane.resize(minSize);
|
||||
} else {
|
||||
let size = Math.floor(
|
||||
(parseInt(localStorage?.chatControlsSize) / container.clientWidth) * 100
|
||||
);
|
||||
if (size < minSize) pane.resize(minSize);
|
||||
// If controls were persisted as open, set the pane to the saved size
|
||||
if ($showControls && pane) {
|
||||
openPane();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
paneReady = true;
|
||||
}, 0);
|
||||
|
||||
const container = document.getElementById('chat-container') as HTMLElement;
|
||||
if (!container) return;
|
||||
|
||||
minSize = Math.floor((350 / container.clientWidth) * 100);
|
||||
resizeObserver = new ResizeObserver((entries) => {
|
||||
for (let entry of entries) {
|
||||
const width = entry.contentRect.width;
|
||||
minSize = Math.floor((350 / width) * 100);
|
||||
if ($showControls) {
|
||||
if (pane && pane.isExpanded() && pane.getSize() < minSize) {
|
||||
pane.resize(minSize);
|
||||
} else {
|
||||
let size = Math.floor(
|
||||
(parseInt(localStorage?.chatControlsSize) / container.clientWidth) * 100
|
||||
);
|
||||
if (size < minSize && pane) pane.resize(minSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
resizeObserver.observe(container);
|
||||
});
|
||||
resizeObserver.observe(container);
|
||||
};
|
||||
init();
|
||||
|
||||
document.addEventListener('mousedown', onMouseDown);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
|
||||
setTimeout(() => {
|
||||
paneReady = true;
|
||||
}, 0);
|
||||
|
||||
// If controls were persisted as open, set the pane to the saved size
|
||||
if ($showControls && pane) {
|
||||
openPane();
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
paneReady = false;
|
||||
if (!largeScreen) {
|
||||
showControls.set(false);
|
||||
}
|
||||
mediaQuery.removeEventListener('change', handleMediaQuery);
|
||||
document.removeEventListener('mousedown', onMouseDown);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
return () => {
|
||||
isDestroyed = true;
|
||||
paneReady = false;
|
||||
resizeObserver?.disconnect();
|
||||
if (!largeScreen) {
|
||||
showControls.set(false);
|
||||
}
|
||||
mediaQuery.removeEventListener('change', handleMediaQuery);
|
||||
document.removeEventListener('mousedown', onMouseDown);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
};
|
||||
});
|
||||
|
||||
const closeHandler = () => {
|
||||
|
||||
Reference in New Issue
Block a user