Timothy Jaeryang Baek 1 mēnesi atpakaļ
vecāks
revīzija
b94de4f002

+ 2 - 2
backend/open_webui/main.py

@@ -1191,6 +1191,7 @@ async def get_app_config(request: Request):
             {
             {
                 "default_models": app.state.config.DEFAULT_MODELS,
                 "default_models": app.state.config.DEFAULT_MODELS,
                 "default_prompt_suggestions": app.state.config.DEFAULT_PROMPT_SUGGESTIONS,
                 "default_prompt_suggestions": app.state.config.DEFAULT_PROMPT_SUGGESTIONS,
+                "user_count": user_count,
                 "code": {
                 "code": {
                     "engine": app.state.config.CODE_EXECUTION_ENGINE,
                     "engine": app.state.config.CODE_EXECUTION_ENGINE,
                 },
                 },
@@ -1214,11 +1215,10 @@ async def get_app_config(request: Request):
                     "api_key": GOOGLE_DRIVE_API_KEY.value,
                     "api_key": GOOGLE_DRIVE_API_KEY.value,
                 },
                 },
                 "onedrive": {"client_id": ONEDRIVE_CLIENT_ID.value},
                 "onedrive": {"client_id": ONEDRIVE_CLIENT_ID.value},
+                "license_metadata": app.state.LICENSE_METADATA,
                 **(
                 **(
                     {
                     {
-                        "record_count": user_count,
                         "active_entries": app.state.USER_COUNT,
                         "active_entries": app.state.USER_COUNT,
-                        "license_metadata": app.state.LICENSE_METADATA,
                     }
                     }
                     if user.role == "admin"
                     if user.role == "admin"
                     else {}
                     else {}

+ 40 - 9
src/lib/components/admin/Settings/General.svelte

@@ -1,4 +1,6 @@
 <script lang="ts">
 <script lang="ts">
+	import DOMPurify from 'dompurify';
+
 	import { getBackendConfig, getVersionUpdates, getWebhookUrl, updateWebhookUrl } from '$lib/apis';
 	import { getBackendConfig, getVersionUpdates, getWebhookUrl, updateWebhookUrl } from '$lib/apis';
 	import {
 	import {
 		getAdminConfig,
 		getAdminConfig,
@@ -220,15 +222,44 @@
 								<div class="">
 								<div class="">
 									{$i18n.t('License')}
 									{$i18n.t('License')}
 								</div>
 								</div>
-								<a
-									class=" text-xs text-gray-500 hover:underline"
-									href="https://docs.openwebui.com/enterprise"
-									target="_blank"
-								>
-									{$i18n.t(
-										'Upgrade to a licensed plan for enhanced capabilities, including custom theming and branding, and dedicated support.'
-									)}
-								</a>
+
+								{#if $config?.license_metadata}
+									<a
+										href="https://docs.openwebui.com/enterprise"
+										target="_blank"
+										class="text-gray-500 mt-0.5"
+									>
+										<span class=" capitalize text-black dark:text-white"
+											>{$config?.license_metadata?.type}
+											license</span
+										>
+										registered to
+										<span class=" capitalize text-black dark:text-white"
+											>{$config?.license_metadata?.organization_name}</span
+										>
+										for
+										<span class=" font-medium text-black dark:text-white"
+											>{$config?.license_metadata?.seats ?? 'Unlimited'} users.</span
+										>
+									</a>
+									{#if $config?.license_metadata?.html}
+										<div class="mt-0.5">
+											{@html DOMPurify.sanitize($config?.license_metadata?.html)}
+										</div>
+									{/if}
+								{:else}
+									<a
+										class=" text-xs hover:underline"
+										href="https://docs.openwebui.com/enterprise"
+										target="_blank"
+									>
+										<span class="text-gray-500">
+											{$i18n.t(
+												'Upgrade to a licensed plan for enhanced capabilities, including custom theming and branding, and dedicated support.'
+											)}
+										</span>
+									</a>
+								{/if}
 							</div>
 							</div>
 
 
 							<!-- <button
 							<!-- <button

+ 34 - 2
src/lib/components/admin/Users/UserList.svelte

@@ -28,6 +28,7 @@
 	import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
 	import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
 	import ChevronDown from '$lib/components/icons/ChevronDown.svelte';
 	import ChevronDown from '$lib/components/icons/ChevronDown.svelte';
 	import About from '$lib/components/chat/Settings/About.svelte';
 	import About from '$lib/components/chat/Settings/About.svelte';
+	import Banner from '$lib/components/common/Banner.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -124,12 +125,43 @@
 />
 />
 <UserChatsModal bind:show={showUserChatsModal} user={selectedUser} />
 <UserChatsModal bind:show={showUserChatsModal} user={selectedUser} />
 
 
+{#if ($config?.license_metadata?.seats ?? null) !== null && users.length > $config?.license_metadata?.seats}
+	<div class=" mt-1 mb-2 text-xs text-red-500">
+		<Banner
+			className="mx-0"
+			banner={{
+				type: 'error',
+				title: 'License Error',
+				content:
+					'Exceeded the number of seats in your license. Please contact support to increase the number of seats.',
+				dismissable: true
+			}}
+		/>
+	</div>
+{/if}
+
 <div class="mt-0.5 mb-2 gap-1 flex flex-col md:flex-row justify-between">
 <div class="mt-0.5 mb-2 gap-1 flex flex-col md:flex-row justify-between">
 	<div class="flex md:self-center text-lg font-medium px-0.5">
 	<div class="flex md:self-center text-lg font-medium px-0.5">
-		{$i18n.t('Users')}
+		<div class="flex-shrink-0">
+			{$i18n.t('Users')}
+		</div>
 		<div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-50 dark:bg-gray-850" />
 		<div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-50 dark:bg-gray-850" />
 
 
-		<span class="text-lg font-medium text-gray-500 dark:text-gray-300">{users.length}</span>
+		{#if ($config?.license_metadata?.seats ?? null) !== null}
+			{#if users.length > $config?.license_metadata?.seats}
+				<span class="text-lg font-medium text-red-500"
+					>{users.length} of {$config?.license_metadata?.seats}
+					<span class="text-sm font-normal">available users</span></span
+				>
+			{:else}
+				<span class="text-lg font-medium text-gray-500 dark:text-gray-300"
+					>{users.length} of {$config?.license_metadata?.seats}
+					<span class="text-sm font-normal">available users</span></span
+				>
+			{/if}
+		{:else}
+			<span class="text-lg font-medium text-gray-500 dark:text-gray-300">{users.length}</span>
+		{/if}
 	</div>
 	</div>
 
 
 	<div class="flex gap-1">
 	<div class="flex gap-1">

+ 12 - 0
src/lib/components/chat/Chat.svelte

@@ -1940,6 +1940,18 @@
 				{#if $banners.length > 0 && !history.currentId && !$chatId && selectedModels.length <= 1}
 				{#if $banners.length > 0 && !history.currentId && !$chatId && selectedModels.length <= 1}
 					<div class="absolute top-12 left-0 right-0 w-full z-30">
 					<div class="absolute top-12 left-0 right-0 w-full z-30">
 						<div class=" flex flex-col gap-1 w-full">
 						<div class=" flex flex-col gap-1 w-full">
+							{#if ($config?.license_metadata?.seats ?? null) !== null && $config?.user_count > $config?.license_metadata?.seats}
+								<Banner
+									banner={{
+										type: 'error',
+										title: 'License Error',
+										content: $i18n.t(
+											'Exceeded the number of seats in your license. Please contact support to increase the number of seats.'
+										)
+									}}
+								/>
+							{/if}
+
 							{#each $banners.filter( (b) => (b.dismissible ? !JSON.parse(localStorage.getItem('dismissedBannerIds') ?? '[]').includes(b.id) : true) ) as banner}
 							{#each $banners.filter( (b) => (b.dismissible ? !JSON.parse(localStorage.getItem('dismissedBannerIds') ?? '[]').includes(b.id) : true) ) as banner}
 								<Banner
 								<Banner
 									{banner}
 									{banner}

+ 11 - 3
src/lib/components/chat/Settings/About.svelte

@@ -136,6 +136,17 @@
 		</div>
 		</div>
 
 
 		<div>
 		<div>
+			{#if $config?.license_metadata}
+				<div class="mb-2 text-xs">
+					{#if !$WEBUI_NAME.includes('Open WebUI')}
+						<span class=" text-gray-500 dark:text-gray-300 font-medium">{$WEBUI_NAME}</span> -
+					{/if}
+
+					<span class=" capitalize">{$config?.license_metadata?.type}</span> license purchased by
+					<span class=" capitalize">{$config?.license_metadata?.organization_name}</span>
+				</div>
+			{/if}
+
 			<pre
 			<pre
 				class="text-xs text-gray-400 dark:text-gray-500">Copyright (c) {new Date().getFullYear()} <a
 				class="text-xs text-gray-400 dark:text-gray-500">Copyright (c) {new Date().getFullYear()} <a
 					href="https://openwebui.com"
 					href="https://openwebui.com"
@@ -172,9 +183,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 		</div>
 		</div>
 
 
 		<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
 		<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
-			{#if !$WEBUI_NAME.includes('Open WebUI')}
-				<span class=" text-gray-500 dark:text-gray-300 font-medium">{$WEBUI_NAME}</span> -
-			{/if}
 			{$i18n.t('Created by')}
 			{$i18n.t('Created by')}
 			<a
 			<a
 				class=" text-gray-500 dark:text-gray-300 font-medium"
 				class=" text-gray-500 dark:text-gray-300 font-medium"

+ 2 - 1
src/lib/components/common/Banner.svelte

@@ -16,6 +16,7 @@
 		dismissable: true,
 		dismissable: true,
 		timestamp: Math.floor(Date.now() / 1000)
 		timestamp: Math.floor(Date.now() / 1000)
 	};
 	};
+	export let className = 'mx-4';
 
 
 	export let dismissed = false;
 	export let dismissed = false;
 
 
@@ -41,7 +42,7 @@
 {#if !dismissed}
 {#if !dismissed}
 	{#if mounted}
 	{#if mounted}
 		<div
 		<div
-			class=" top-0 left-0 right-0 p-2 mx-4 px-3 flex justify-center items-center relative rounded-xl border border-gray-100 dark:border-gray-850 text-gray-800 dark:text-gary-100 bg-white dark:bg-gray-900 backdrop-blur-xl z-30"
+			class="{className} top-0 left-0 right-0 p-2 px-3 flex justify-center items-center relative rounded-xl border border-gray-100 dark:border-gray-850 text-gray-800 dark:text-gary-100 bg-white dark:bg-gray-900 backdrop-blur-xl z-30"
 			transition:fade={{ delay: 100, duration: 300 }}
 			transition:fade={{ delay: 100, duration: 300 }}
 		>
 		>
 			<div class=" flex flex-col md:flex-row md:items-center flex-1 text-sm w-fit gap-1.5">
 			<div class=" flex flex-col md:flex-row md:items-center flex-1 text-sm w-fit gap-1.5">