feat: notes scaffolding

This commit is contained in:
Timothy Jaeryang Baek 2025-05-01 16:39:36 +04:00
parent 2062d3434e
commit 5d5e351937
13 changed files with 121 additions and 9 deletions

View File

@ -1178,6 +1178,11 @@ ENABLE_CHANNELS = PersistentConfig(
os.environ.get("ENABLE_CHANNELS", "False").lower() == "true",
)
ENABLE_NOTES = PersistentConfig(
"ENABLE_NOTES",
"notes.enable",
os.environ.get("ENABLE_NOTES", "True").lower() == "true",
)
ENABLE_EVALUATION_ARENA_MODELS = PersistentConfig(
"ENABLE_EVALUATION_ARENA_MODELS",

View File

@ -274,6 +274,7 @@ from open_webui.config import (
ENABLE_API_KEY_ENDPOINT_RESTRICTIONS,
API_KEY_ALLOWED_ENDPOINTS,
ENABLE_CHANNELS,
ENABLE_NOTES,
ENABLE_COMMUNITY_SHARING,
ENABLE_MESSAGE_RATING,
ENABLE_USER_WEBHOOKS,
@ -570,6 +571,7 @@ app.state.config.MODEL_ORDER_LIST = MODEL_ORDER_LIST
app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS
app.state.config.ENABLE_NOTES = ENABLE_NOTES
app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING
app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING
app.state.config.ENABLE_USER_WEBHOOKS = ENABLE_USER_WEBHOOKS
@ -1321,6 +1323,7 @@ async def get_app_config(request: Request):
{
"enable_direct_connections": app.state.config.ENABLE_DIRECT_CONNECTIONS,
"enable_channels": app.state.config.ENABLE_CHANNELS,
"enable_notes": app.state.config.ENABLE_NOTES,
"enable_web_search": app.state.config.ENABLE_WEB_SEARCH,
"enable_code_execution": app.state.config.ENABLE_CODE_EXECUTION,
"enable_code_interpreter": app.state.config.ENABLE_CODE_INTERPRETER,

View File

@ -689,6 +689,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)):
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
}
@ -705,6 +706,7 @@ class AdminConfig(BaseModel):
ENABLE_COMMUNITY_SHARING: bool
ENABLE_MESSAGE_RATING: bool
ENABLE_CHANNELS: bool
ENABLE_NOTES: bool
ENABLE_USER_WEBHOOKS: bool
@ -725,6 +727,7 @@ async def update_admin_config(
)
request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS
request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES
if form_data.DEFAULT_USER_ROLE in ["pending", "user", "admin"]:
request.app.state.config.DEFAULT_USER_ROLE = form_data.DEFAULT_USER_ROLE
@ -749,11 +752,12 @@ async def update_admin_config(
"ENABLE_API_KEY": request.app.state.config.ENABLE_API_KEY,
"ENABLE_API_KEY_ENDPOINT_RESTRICTIONS": request.app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS,
"API_KEY_ALLOWED_ENDPOINTS": request.app.state.config.API_KEY_ALLOWED_ENDPOINTS,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"DEFAULT_USER_ROLE": request.app.state.config.DEFAULT_USER_ROLE,
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
}

View File

@ -601,6 +601,14 @@
<Switch bind:state={adminConfig.ENABLE_MESSAGE_RATING} />
</div>
<div class="mb-2.5 flex w-full items-center justify-between pr-2">
<div class=" self-center text-xs font-medium">
{$i18n.t('Notes')} ({$i18n.t('Beta')})
</div>
<Switch bind:state={adminConfig.ENABLE_NOTES} />
</div>
<div class="mb-2.5 flex w-full items-center justify-between pr-2">
<div class=" self-center text-xs font-medium">
{$i18n.t('Channels')} ({$i18n.t('Beta')})

View File

@ -609,6 +609,48 @@
</div>
{/if}
{#if $config?.features?.enable_notes ?? false}
<div class="px-1.5 flex justify-center text-gray-800 dark:text-gray-200">
<a
class="grow flex items-center space-x-3 rounded-lg px-2 py-[7px] hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/notes"
on:click={() => {
selectedChatId = null;
chatId.set('');
if ($mobile) {
showSidebar.set(false);
}
}}
draggable="false"
>
<div class="self-center">
<svg
class="size-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 3v4a1 1 0 0 1-1 1H5m4 8h6m-6-4h6m4-8v16a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7.914a1 1 0 0 1 .293-.707l3.914-3.914A1 1 0 0 1 9.914 3H18a1 1 0 0 1 1 1Z"
/>
</svg>
</div>
<div class="flex self-center translate-y-[0.5px]">
<div class=" self-center font-medium text-sm font-primary">{$i18n.t('Notes')}</div>
</div>
</a>
</div>
{/if}
<div class="relative {$temporaryChatEnabled ? 'opacity-20' : ''}">
{#if $temporaryChatEnabled}
<div class="absolute z-40 w-full h-full flex justify-center"></div>

View File

@ -20,7 +20,7 @@
<svelte:head>
<title>
{$i18n.t('Admin Panel')} | {$WEBUI_NAME}
{$i18n.t('Admin Panel')} {$WEBUI_NAME}
</title>
</svelte:head>

View File

@ -11,7 +11,7 @@
<svelte:head>
<title>
{$i18n.t('Home')} | {$WEBUI_NAME}
{$i18n.t('Home')} {$WEBUI_NAME}
</title>
</svelte:head>

View File

@ -0,0 +1,50 @@
<script lang="ts">
import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, showSidebar, functions, config } from '$lib/stores';
import MenuLines from '$lib/components/icons/MenuLines.svelte';
import { page } from '$app/stores';
const i18n = getContext('i18n');
onMount(async () => {
if (!$config?.features?.enable_notes) {
// If the feature is not enabled, redirect to the home page
goto('/');
}
});
</script>
<svelte:head>
<title>
{$i18n.t('Notes')}{$WEBUI_NAME}
</title>
</svelte:head>
<div
class=" flex flex-col w-full h-screen max-h-[100dvh] transition-width duration-200 ease-in-out {$showSidebar
? 'md:max-w-[calc(100%-260px)]'
: ''} max-w-full"
>
<nav class=" px-2.5 pt-1 backdrop-blur-xl w-full drag-region">
<div class=" flex items-center">
<div class="{$showSidebar ? 'md:hidden' : ''} flex flex-none items-center self-end">
<button
id="sidebar-toggle-button"
class="cursor-pointer p-1.5 flex rounded-xl hover:bg-gray-100 dark:hover:bg-gray-850 transition"
on:click={() => {
showSidebar.set(!$showSidebar);
}}
aria-label="Toggle Sidebar"
>
<div class=" m-auto self-center">
<MenuLines />
</div>
</button>
</div>
</div>
</nav>
<div class=" flex-1 max-h-full overflow-y-auto">
<slot />
</div>
</div>

View File

View File

@ -11,7 +11,7 @@
<svelte:head>
<title>
{$i18n.t('Playground')} | {$WEBUI_NAME}
{$i18n.t('Playground')} {$WEBUI_NAME}
</title>
</svelte:head>

View File

@ -45,7 +45,7 @@
<svelte:head>
<title>
{$i18n.t('Workspace')} | {$WEBUI_NAME}
{$i18n.t('Workspace')} {$WEBUI_NAME}
</title>
</svelte:head>

View File

@ -227,7 +227,7 @@
if ($isLastActiveTab) {
if ($settings?.notificationEnabled ?? false) {
new Notification(`${title} | Open WebUI`, {
new Notification(`${title} Open WebUI`, {
body: content,
icon: `${WEBUI_BASE_URL}/static/favicon.png`
});
@ -376,7 +376,7 @@
if (type === 'message') {
if ($isLastActiveTab) {
if ($settings?.notificationEnabled ?? false) {
new Notification(`${data?.user?.name} (#${event?.channel?.name}) | Open WebUI`, {
new Notification(`${data?.user?.name} (#${event?.channel?.name}) Open WebUI`, {
body: data?.content,
icon: data?.user?.profile_image_url ?? `${WEBUI_BASE_URL}/static/favicon.png`
});

View File

@ -145,7 +145,7 @@
<svelte:head>
<title>
{title
? `${title.length > 30 ? `${title.slice(0, 30)}...` : title} | ${$WEBUI_NAME}`
? `${title.length > 30 ? `${title.slice(0, 30)}...` : title} ${$WEBUI_NAME}`
: `${$WEBUI_NAME}`}
</title>
</svelte:head>