Admin default (#4032)

* clean up

* minor cleanup

* building

* update agnetic message look

* k

* fix alembic history
This commit is contained in:
pablonyx 2025-02-18 18:31:54 -08:00 committed by GitHub
parent 630bdf71a3
commit 9635522de8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 113 additions and 60 deletions

View File

@ -0,0 +1,31 @@
"""nullable preferences
Revision ID: b388730a2899
Revises: 1a03d2c2856b
Create Date: 2025-02-17 18:49:22.643902
"""
from alembic import op
# revision identifiers, used by Alembic.
revision = "b388730a2899"
down_revision = "1a03d2c2856b"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.alter_column("user", "temperature_override_enabled", nullable=True)
op.alter_column("user", "auto_scroll", nullable=True)
def downgrade() -> None:
# Ensure no null values before making columns non-nullable
op.execute(
'UPDATE "user" SET temperature_override_enabled = false WHERE temperature_override_enabled IS NULL'
)
op.execute('UPDATE "user" SET auto_scroll = false WHERE auto_scroll IS NULL')
op.alter_column("user", "temperature_override_enabled", nullable=False)
op.alter_column("user", "auto_scroll", nullable=False)

View File

@ -148,11 +148,12 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
putting here for simpicity
"""
# if specified, controls the assistants that are shown to the user + their order
# if not specified, all assistants are shown
temperature_override_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
auto_scroll: Mapped[bool] = mapped_column(Boolean, default=True)
temperature_override_enabled: Mapped[bool | None] = mapped_column(
Boolean, default=None
)
auto_scroll: Mapped[bool | None] = mapped_column(Boolean, default=None)
shortcut_enabled: Mapped[bool] = mapped_column(Boolean, default=False)
chosen_assistants: Mapped[list[int] | None] = mapped_column(
postgresql.JSONB(), nullable=True, default=None
)

View File

@ -45,9 +45,11 @@ class UserPreferences(BaseModel):
hidden_assistants: list[int] = []
visible_assistants: list[int] = []
default_model: str | None = None
auto_scroll: bool | None = None
pinned_assistants: list[int] | None = None
shortcut_enabled: bool | None = None
# These will default to workspace settings on the frontend if not set
auto_scroll: bool | None = None
temperature_override_enabled: bool | None = None
@ -86,12 +88,12 @@ class UserInfo(BaseModel):
preferences=(
UserPreferences(
shortcut_enabled=user.shortcut_enabled,
auto_scroll=user.auto_scroll,
chosen_assistants=user.chosen_assistants,
default_model=user.default_model,
hidden_assistants=user.hidden_assistants,
pinned_assistants=user.pinned_assistants,
visible_assistants=user.visible_assistants,
auto_scroll=user.auto_scroll,
temperature_override_enabled=user.temperature_override_enabled,
)
),

View File

@ -46,7 +46,9 @@ class Settings(BaseModel):
application_status: ApplicationStatus = ApplicationStatus.ACTIVE
anonymous_user_enabled: bool | None = None
pro_search_disabled: bool | None = None
auto_scroll: bool | None = None
temperature_override_enabled: bool = False
auto_scroll: bool = False
class UserSettings(Settings):

View File

@ -213,12 +213,23 @@ export function SettingsForm() {
<Title className="mb-4">Workspace Settings</Title>
<Checkbox
label="Auto-scroll"
sublabel="If set, the chat window will automatically scroll to the bottom as new lines of text are generated by the AI model."
sublabel="If set, the chat window will automatically scroll to the bottom as new lines of text are generated by the AI model. This can be overridden by individual user settings."
checked={settings.auto_scroll}
onChange={(e) =>
handleToggleSettingsField("auto_scroll", e.target.checked)
}
/>
<Checkbox
label="Override default temperature"
sublabel="If set, users will be able to override the default temperature for each assistant."
checked={settings.temperature_override_enabled}
onChange={(e) =>
handleToggleSettingsField(
"temperature_override_enabled",
e.target.checked
)
}
/>
<Checkbox
label="Anonymous Users"
sublabel="If set, users will not be required to sign in to use Onyx."

View File

@ -13,6 +13,7 @@ export interface Settings {
pro_search_disabled: boolean | null;
application_status: ApplicationStatus;
auto_scroll: boolean;
temperature_override_enabled: boolean;
}
export enum NotificationType {
@ -54,7 +55,6 @@ export interface EnterpriseSettings {
custom_popup_header: string | null;
custom_popup_content: string | null;
enable_consent_screen: boolean | null;
auto_scroll: boolean;
}
export interface CombinedSettings {

View File

@ -1870,9 +1870,7 @@ export function ChatPage({
});
const autoScrollEnabled =
user?.preferences?.auto_scroll == null
? settings?.enterpriseSettings?.auto_scroll || false
: user?.preferences?.auto_scroll! && !agenticGenerating;
(user?.preferences?.auto_scroll && !agenticGenerating) ?? false;
useScrollonStream({
chatState: currentSessionChatState,

View File

@ -537,7 +537,6 @@ export const AgenticMessage = ({
{includeMessageSwitcher && (
<div className="-mx-1 mr-auto">
<MessageSwitcher
disableForStreaming={!isComplete}
currentPage={currentMessageInd + 1}
totalPages={otherMessagesCanSwitchTo.length}
handlePrevious={() => {
@ -624,7 +623,6 @@ export const AgenticMessage = ({
{includeMessageSwitcher && (
<div className="-mx-1 mr-auto">
<MessageSwitcher
disableForStreaming={!isComplete}
currentPage={currentMessageInd + 1}
totalPages={otherMessagesCanSwitchTo.length}
handlePrevious={() => {
@ -703,52 +701,27 @@ function MessageSwitcher({
totalPages,
handlePrevious,
handleNext,
disableForStreaming,
}: {
currentPage: number;
totalPages: number;
handlePrevious: () => void;
handleNext: () => void;
disableForStreaming?: boolean;
}) {
return (
<div className="flex items-center text-sm space-x-0.5">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div>
<Hoverable
icon={FiChevronLeft}
onClick={currentPage === 1 ? undefined : handlePrevious}
/>
</div>
</TooltipTrigger>
<TooltipContent>
{disableForStreaming ? "Disabled" : "Previous"}
</TooltipContent>
</Tooltip>
</TooltipProvider>
<Hoverable
icon={FiChevronLeft}
onClick={currentPage === 1 ? undefined : handlePrevious}
/>
<span className="text-text-darker select-none">
{currentPage} / {totalPages}
{disableForStreaming ? "Complete" : "Generating"}
</span>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div>
<Hoverable
icon={FiChevronRight}
onClick={currentPage === totalPages ? undefined : handleNext}
/>
</div>
</TooltipTrigger>
<TooltipContent>
{disableForStreaming ? "Disabled" : "Next"}
</TooltipContent>
</Tooltip>
</TooltipProvider>
<Hoverable
icon={FiChevronRight}
onClick={currentPage === totalPages ? undefined : handleNext}
/>
</div>
);
}

View File

@ -154,11 +154,9 @@ export function UserSettingsModal({
});
}
};
const defaultProvider = llmProviders.find(
(llmProvider) => llmProvider.is_default_provider
);
const settings = useContext(SettingsContext);
const autoScroll = settings?.enterpriseSettings?.auto_scroll;
const autoScroll = settings?.settings?.auto_scroll;
const checked =
user?.preferences?.auto_scroll === null

View File

@ -55,7 +55,7 @@ export function WhitelabelingForm() {
<div>
<Formik
initialValues={{
auto_scroll: enterpriseSettings?.auto_scroll || false,
auto_scroll: settings?.settings?.auto_scroll || false,
application_name: enterpriseSettings?.application_name || null,
use_custom_logo: enterpriseSettings?.use_custom_logo || false,
use_custom_logotype: enterpriseSettings?.use_custom_logotype || false,

View File

@ -1,3 +1,4 @@
"use client";
import { CombinedSettings } from "@/app/admin/settings/interfaces";
import { UserProvider } from "../user/UserProvider";
import { ProviderContextProvider } from "../chat/ProviderContext";
@ -27,9 +28,9 @@ export const AppProvider = ({
hasImageCompatibleModel,
}: AppProviderProps) => {
return (
<UserProvider user={user}>
<ProviderContextProvider>
<SettingsProvider settings={settings}>
<SettingsProvider settings={settings}>
<UserProvider settings={settings} user={user}>
<ProviderContextProvider>
<AssistantsProvider
initialAssistants={assistants}
hasAnyConnectors={hasAnyConnectors}
@ -37,8 +38,8 @@ export const AppProvider = ({
>
{children}
</AssistantsProvider>
</SettingsProvider>
</ProviderContextProvider>
</UserProvider>
</ProviderContextProvider>
</UserProvider>
</SettingsProvider>
);
};

View File

@ -52,6 +52,7 @@ export async function fetchSettingsSS(): Promise<CombinedSettings | null> {
needs_reindexing: false,
anonymous_user_enabled: false,
pro_search_disabled: false,
temperature_override_enabled: true,
};
} else {
throw new Error(

View File

@ -4,6 +4,8 @@ import React, { createContext, useContext, useState, useEffect } from "react";
import { User, UserRole } from "@/lib/types";
import { getCurrentUser } from "@/lib/user";
import { usePostHog } from "posthog-js/react";
import { CombinedSettings } from "@/app/admin/settings/interfaces";
import { SettingsContext } from "../settings/SettingsProvider";
interface UserContextType {
user: User | null;
@ -26,14 +28,47 @@ const UserContext = createContext<UserContextType | undefined>(undefined);
export function UserProvider({
children,
user,
settings,
}: {
children: React.ReactNode;
user: User | null;
settings: CombinedSettings;
}) {
const [upToDateUser, setUpToDateUser] = useState<User | null>(user);
const updatedSettings = useContext(SettingsContext);
const posthog = usePostHog();
// For auto_scroll and temperature_override_enabled:
// - If user has a preference set, use that
// - Otherwise, use the workspace setting if available
function mergeUserPreferences(
currentUser: User | null,
currentSettings: CombinedSettings | null
): User | null {
if (!currentUser) return null;
return {
...currentUser,
preferences: {
...currentUser.preferences,
auto_scroll:
currentUser.preferences?.auto_scroll ??
currentSettings?.settings?.auto_scroll ??
false,
temperature_override_enabled:
currentUser.preferences?.temperature_override_enabled ??
currentSettings?.settings?.temperature_override_enabled ??
false,
},
};
}
const [upToDateUser, setUpToDateUser] = useState<User | null>(
mergeUserPreferences(user, settings)
);
useEffect(() => {
setUpToDateUser(mergeUserPreferences(user, updatedSettings));
}, [user, updatedSettings]);
useEffect(() => {
if (!posthog) return;