Skip to content

Commit 6137f7c

Browse files
authored
Merge pull request open-webui#22121 from open-webui/dev
0.8.7
2 parents 9c9a18d + 832d018 commit 6137f7c

6 files changed

Lines changed: 73 additions & 51 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.8.7] - 2026-03-01
9+
10+
### Fixed
11+
12+
- 🔒 **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)
13+
- 🧠 **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)
14+
- 💾 **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)
15+
- ⚡ **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)
16+
817
## [0.8.6] - 2026-03-01
918

1019
### Added

backend/open_webui/utils/access_control/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ def has_connection_access(
163163
based on ``config.access_grants`` within the connection dict.
164164
165165
- Admin with BYPASS_ADMIN_ACCESS_CONTROL → always allowed
166-
- Empty / missing access_grants → allowed for all users
167-
- Otherwise → delegates to ``has_access``
166+
- Missing, None, or empty access_grants → private, admin-only
167+
- access_grants has entries → delegates to ``has_access``
168168
"""
169169
from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL
170170

@@ -175,9 +175,6 @@ def has_connection_access(
175175
user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user.id)}
176176

177177
access_grants = (connection.get("config") or {}).get("access_grants", [])
178-
if not access_grants:
179-
return True
180-
181178
return has_access(user.id, "read", access_grants, user_group_ids)
182179

183180

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "open-webui",
3-
"version": "0.8.6",
3+
"version": "0.8.7",
44
"private": true,
55
"scripts": {
66
"dev": "npm run pyodide:fetch && vite dev --host",

src/lib/components/chat/Chat.svelte

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,11 @@
964964
};
965965
966966
$: if (history) {
967-
getContents();
967+
cancelAnimationFrame(contentsRAF);
968+
contentsRAF = requestAnimationFrame(() => {
969+
getContents();
970+
contentsRAF = null;
971+
});
968972
} else {
969973
artifactContents.set([]);
970974
}
@@ -1294,6 +1298,7 @@
12941298
};
12951299
12961300
let scrollRAF = null;
1301+
let contentsRAF = null;
12971302
const scheduleScrollToBottom = () => {
12981303
if (!scrollRAF) {
12991304
scrollRAF = requestAnimationFrame(async () => {
@@ -2719,6 +2724,7 @@
27192724
id: uuidv4(),
27202725
title: title.length > 50 ? `${title.slice(0, 50)}...` : title,
27212726
models: selectedModels,
2727+
params: params,
27222728
history: history,
27232729
messages: messages,
27242730
timestamp: Date.now()

src/lib/components/chat/ChatControls.svelte

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,8 @@
5050
export let files;
5151
export let modelId;
5252
53-
export let pane;
53+
export let pane: Pane | null = null;
5454
55-
let mediaQuery;
5655
let largeScreen = false;
5756
let dragged = false;
5857
let minSize = 0;
@@ -172,56 +171,67 @@
172171
dragged = false;
173172
};
174173
175-
onMount(async () => {
176-
mediaQuery = window.matchMedia('(min-width: 1024px)');
174+
onMount(() => {
175+
const mediaQuery = window.matchMedia('(min-width: 1024px)');
177176
mediaQuery.addEventListener('change', handleMediaQuery);
178177
handleMediaQuery(mediaQuery);
179178
179+
let resizeObserver: ResizeObserver | null = null;
180+
let isDestroyed = false;
181+
180182
// Wait for Svelte to render the Pane after largeScreen changed
181-
await tick();
182-
183-
const container = document.getElementById('chat-container');
184-
minSize = Math.floor((350 / container.clientWidth) * 100);
185-
186-
const resizeObserver = new ResizeObserver((entries) => {
187-
for (let entry of entries) {
188-
const width = entry.contentRect.width;
189-
minSize = Math.floor((350 / width) * 100);
190-
if ($showControls) {
191-
if (pane && pane.isExpanded() && pane.getSize() < minSize) {
192-
pane.resize(minSize);
193-
} else {
194-
let size = Math.floor(
195-
(parseInt(localStorage?.chatControlsSize) / container.clientWidth) * 100
196-
);
197-
if (size < minSize) pane.resize(minSize);
183+
const init = async () => {
184+
await tick();
185+
186+
if (isDestroyed) return;
187+
188+
// If controls were persisted as open, set the pane to the saved size
189+
if ($showControls && pane) {
190+
openPane();
191+
}
192+
193+
setTimeout(() => {
194+
paneReady = true;
195+
}, 0);
196+
197+
const container = document.getElementById('chat-container') as HTMLElement;
198+
if (!container) return;
199+
200+
minSize = Math.floor((350 / container.clientWidth) * 100);
201+
resizeObserver = new ResizeObserver((entries) => {
202+
for (let entry of entries) {
203+
const width = entry.contentRect.width;
204+
minSize = Math.floor((350 / width) * 100);
205+
if ($showControls) {
206+
if (pane && pane.isExpanded() && pane.getSize() < minSize) {
207+
pane.resize(minSize);
208+
} else {
209+
let size = Math.floor(
210+
(parseInt(localStorage?.chatControlsSize) / container.clientWidth) * 100
211+
);
212+
if (size < minSize && pane) pane.resize(minSize);
213+
}
198214
}
199215
}
200-
}
201-
});
202-
resizeObserver.observe(container);
216+
});
217+
resizeObserver.observe(container);
218+
};
219+
init();
203220
204221
document.addEventListener('mousedown', onMouseDown);
205222
document.addEventListener('mouseup', onMouseUp);
206223
207-
setTimeout(() => {
208-
paneReady = true;
209-
}, 0);
210-
211-
// If controls were persisted as open, set the pane to the saved size
212-
if ($showControls && pane) {
213-
openPane();
214-
}
215-
});
216-
217-
onDestroy(() => {
218-
paneReady = false;
219-
if (!largeScreen) {
220-
showControls.set(false);
221-
}
222-
mediaQuery.removeEventListener('change', handleMediaQuery);
223-
document.removeEventListener('mousedown', onMouseDown);
224-
document.removeEventListener('mouseup', onMouseUp);
224+
return () => {
225+
isDestroyed = true;
226+
paneReady = false;
227+
resizeObserver?.disconnect();
228+
if (!largeScreen) {
229+
showControls.set(false);
230+
}
231+
mediaQuery.removeEventListener('change', handleMediaQuery);
232+
document.removeEventListener('mousedown', onMouseDown);
233+
document.removeEventListener('mouseup', onMouseUp);
234+
};
225235
});
226236
227237
const closeHandler = () => {

0 commit comments

Comments
 (0)