mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-04 02:33:43 +00:00
feat: optional inline filter toggles in the message input
Add a Settings -> Interface "Inline Filter Toggles" setting (default off). When enabled, the message-input bar shows every toggleable filter as a persistent chip -- greyed when off, highlighted when on -- and clicking a chip toggles its selection in place instead of removing it from the bar. Filters with UserValves expose those via a gear shown on hover, so nothing is lost. Default behavior is unchanged (only selected filters show as removable chips). Restores the inline-toggle behavior some users have asked for (e.g. #17574) without changing the default. No change to selectedFilterIds or the backend.
This commit is contained in:
parent
b1d40f3409
commit
71eb34f835
3 changed files with 75 additions and 18 deletions
|
|
@ -80,6 +80,7 @@
|
|||
import Spinner from '../common/Spinner.svelte';
|
||||
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import Cog6 from '../icons/Cog6.svelte';
|
||||
import GlobeAlt from '../icons/GlobeAlt.svelte';
|
||||
import Photo from '../icons/Photo.svelte';
|
||||
import Wrench from '../icons/Wrench.svelte';
|
||||
|
|
@ -512,6 +513,14 @@
|
|||
.map((id) => ($models.find((model) => model.id === id) || {})?.filters ?? [])
|
||||
.reduce((acc, filters) => acc.filter((f1) => filters.some((f2) => f2.id === f1.id)));
|
||||
|
||||
// With the `inlineFilterToggles` setting on, every available toggle filter is
|
||||
// shown as a persistent chip (greyed when off, toggled in place); otherwise the
|
||||
// default shows only the selected filters as removable chips.
|
||||
let filterChips = [];
|
||||
$: filterChips = ($settings?.inlineFilterToggles ?? false)
|
||||
? toggleFilters
|
||||
: selectedFilterIds.map((id) => toggleFilters.find((f) => f.id === id)).filter((f) => f);
|
||||
|
||||
let showToolsButton = false;
|
||||
$: showToolsButton = ($tools ?? []).length > 0 || ($toolServers ?? []).length > 0;
|
||||
|
||||
|
|
@ -1791,29 +1800,37 @@
|
|||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
{#each selectedFilterIds as filterId (filterId)}
|
||||
{@const filter = toggleFilters.find((f) => f.id === filterId)}
|
||||
{#each filterChips as filter (filter.id)}
|
||||
{#if filter}
|
||||
<Tooltip content={filter?.name} placement="top">
|
||||
<button
|
||||
on:click|preventDefault={() => {
|
||||
if (
|
||||
if ($settings?.inlineFilterToggles ?? false) {
|
||||
// In-place toggle: flip selection, keep the chip visible.
|
||||
if (selectedFilterIds.includes(filter.id)) {
|
||||
selectedFilterIds = selectedFilterIds.filter(
|
||||
(id) => id !== filter.id
|
||||
);
|
||||
} else {
|
||||
selectedFilterIds = [...selectedFilterIds, filter.id];
|
||||
}
|
||||
} else if (
|
||||
filter?.has_user_valves &&
|
||||
($_user?.role === 'admin' ||
|
||||
($_user?.permissions?.chat?.valves ?? true))
|
||||
) {
|
||||
selectedValvesType = 'function';
|
||||
selectedValvesItemId = filterId;
|
||||
selectedValvesItemId = filter.id;
|
||||
showValvesModal = true;
|
||||
} else {
|
||||
selectedFilterIds = selectedFilterIds.filter(
|
||||
(id) => id !== filterId
|
||||
(id) => id !== filter.id
|
||||
);
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
class="group p-[7px] flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden {selectedFilterIds.includes(
|
||||
filterId
|
||||
filter.id
|
||||
)
|
||||
? 'text-sky-500 dark:text-sky-300 bg-sky-50 hover:bg-sky-100 dark:bg-sky-400/10 dark:hover:bg-sky-600/10 border border-sky-200/40 dark:border-sky-500/20'
|
||||
: 'bg-transparent text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 '} capitalize"
|
||||
|
|
@ -1834,18 +1851,36 @@
|
|||
{/if}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="hidden group-hover:block"
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
selectedFilterIds = selectedFilterIds.filter(
|
||||
(id) => id !== filterId
|
||||
);
|
||||
}}
|
||||
>
|
||||
<XMark className="size-4" strokeWidth="1.75" />
|
||||
</div>
|
||||
{#if $settings?.inlineFilterToggles ?? false}
|
||||
{#if filter?.has_user_valves && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.valves ?? true))}
|
||||
<div
|
||||
class="hidden group-hover:block"
|
||||
title={$i18n.t('Settings')}
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
selectedValvesType = 'function';
|
||||
selectedValvesItemId = filter.id;
|
||||
showValvesModal = true;
|
||||
}}
|
||||
>
|
||||
<Cog6 className="size-4" strokeWidth="1.75" />
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
class="hidden group-hover:block"
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
selectedFilterIds = selectedFilterIds.filter(
|
||||
(id) => id !== filter.id
|
||||
);
|
||||
}}
|
||||
>
|
||||
<XMark className="size-4" strokeWidth="1.75" />
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
let responseAutoCopy = false;
|
||||
let widescreenMode = false;
|
||||
let inlineFilterToggles = false;
|
||||
let splitLargeChunks = false;
|
||||
let scrollOnBranchChange = true;
|
||||
let userLocation = false;
|
||||
|
|
@ -242,6 +243,7 @@
|
|||
landingPageMode = $settings?.landingPageMode ?? '';
|
||||
chatBubble = $settings?.chatBubble ?? true;
|
||||
widescreenMode = $settings?.widescreenMode ?? false;
|
||||
inlineFilterToggles = $settings?.inlineFilterToggles ?? false;
|
||||
splitLargeChunks = $settings?.splitLargeChunks ?? false;
|
||||
scrollOnBranchChange = $settings?.scrollOnBranchChange ?? true;
|
||||
|
||||
|
|
@ -740,6 +742,25 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div id="inline-filter-toggles-label" class=" self-center text-xs">
|
||||
{$i18n.t('Inline Filter Toggles')}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 p-1">
|
||||
<Switch
|
||||
ariaLabelledbyId="inline-filter-toggles-label"
|
||||
tooltip={true}
|
||||
bind:state={inlineFilterToggles}
|
||||
on:change={() => {
|
||||
saveSettings({ inlineFilterToggles });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if $user.role === 'admin' || $user?.permissions?.chat?.temporary}
|
||||
<div>
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
|
|
|
|||
|
|
@ -1152,6 +1152,7 @@
|
|||
"Initials": "",
|
||||
"Inject file content into conversation context": "",
|
||||
"Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "",
|
||||
"Inline Filter Toggles": "",
|
||||
"Input": "",
|
||||
"Input Key (e.g. text, unet_name, steps)": "",
|
||||
"Input Variables": "",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue