Compare commits

...

3 Commits

Author SHA1 Message Date
Yuhong Sun
34356a5853 Fix sidebar 2026-03-13 13:56:47 -07:00
Yuhong Sun
82fb535015 Done 2026-03-13 13:55:47 -07:00
Yuhong Sun
6bb9a4970b Small touchups in UI 2026-03-13 13:55:47 -07:00
12 changed files with 72 additions and 27 deletions

View File

@@ -957,7 +957,7 @@ ENTERPRISE_EDITION_ENABLED = (
#####
# Image Generation Configuration (DEPRECATED)
# These environment variables will be deprecated soon.
# To configure image generation, please visit the Image Generation page in the Admin Panel.
# To configure image generation, please visit the Image Generation page in the Admin Settings.
#####
# Azure Image Configurations
AZURE_IMAGE_API_VERSION = os.environ.get("AZURE_IMAGE_API_VERSION") or os.environ.get(

View File

@@ -464,7 +464,7 @@ export default function VoiceConfigurationPage() {
return (
<>
<AdminPageTitle
title="Voice"
title="Voice Mode"
icon={SvgMicrophone}
includeDivider={false}
/>
@@ -484,7 +484,7 @@ export default function VoiceConfigurationPage() {
return (
<>
<AdminPageTitle
title="Voice"
title="Voice Mode"
icon={SvgMicrophone}
includeDivider={false}
/>
@@ -497,7 +497,7 @@ export default function VoiceConfigurationPage() {
return (
<>
<AdminPageTitle icon={SvgAudio} title="Voice" />
<AdminPageTitle icon={SvgAudio} title="Voice Mode" />
<div className="pt-4 pb-4">
<Text as="p" secondaryBody text03>
Speech to text (STT) and text to speech (TTS) capabilities.

View File

@@ -79,7 +79,7 @@ interface SelectedConnectorState {
}
/**
* Build Admin Panel - Connector configuration page
* Build Admin Settings - Connector configuration page
*
* Renders in the center panel area (replacing ChatPanel + OutputPanel).
* Uses SettingsLayouts like AgentEditorPage does.

View File

@@ -22,10 +22,10 @@ export default function NoAgentModal() {
<>
<Text as="p">
As an administrator, you can create a new agent by visiting the
admin panel.
admin settings.
</Text>
<Button width="full" href="/admin/agents">
Go to Admin Panel
Go to Admin Settings
</Button>
</>
) : (

View File

@@ -766,6 +766,7 @@ export default function AppPage({ firstMessage }: ChatPageProps) {
{(appFocus.isNewSession() || appFocus.isAgent()) &&
(state.phase === "idle" ||
state.phase === "classifying") &&
!isLoadingOnboarding &&
(showOnboarding || !user?.personalization?.name) &&
!onboardingDismissed && (
<OnboardingFlow

View File

@@ -977,7 +977,7 @@ function ChatPreferencesSettings() {
<Section gap={0.75}>
<Content
title="Voice"
title="Voice Mode"
sizePreset="main-content"
variant="section"
widthVariant="full"

View File

@@ -92,7 +92,7 @@ export default function ChatDocumentDisplay({
) : (
<SourceIcon sourceType={document.source_type} iconSize={18} />
)}
<Truncated className="line-clamp-2" side="left">
<Truncated className="line-clamp-2" side="left" disable>
{title}
</Truncated>
</div>

View File

@@ -3,7 +3,15 @@
import { MinimalOnyxDocument, OnyxDocument } from "@/lib/search/interfaces";
import ChatDocumentDisplay from "@/sections/document-sidebar/ChatDocumentDisplay";
import { removeDuplicateDocs } from "@/lib/documentUtils";
import { Dispatch, SetStateAction, useMemo, memo } from "react";
import {
Dispatch,
SetStateAction,
useMemo,
memo,
useRef,
useState,
useCallback,
} from "react";
import { getCitations } from "@/app/app/services/packetUtils";
import {
useCurrentMessageTree,
@@ -40,25 +48,30 @@ const buildOnyxDocumentFromFile = (
interface HeaderProps {
children: string;
onClose: () => void;
onClose?: () => void;
isTop?: boolean;
}
function Header({ children, onClose }: HeaderProps) {
function Header({ children, onClose, isTop }: HeaderProps) {
return (
<div className="sticky top-0 z-sticky bg-background-tint-01">
<div className="flex flex-row w-full items-center justify-between gap-2 py-3">
<div className="flex items-center gap-2 w-full px-3">
<SvgSearchMenu className="w-[1.3rem] h-[1.3rem] stroke-text-03" />
{isTop && (
<SvgSearchMenu className="w-[1.3rem] h-[1.3rem] stroke-text-03" />
)}
<Text as="p" headingH3 text03>
{children}
</Text>
</div>
<Button
icon={SvgX}
prominence="tertiary"
onClick={onClose}
tooltip="Close Sidebar"
/>
{onClose && (
<Button
icon={SvgX}
prominence="tertiary"
onClick={onClose}
tooltip="Close Sidebar"
/>
)}
</div>
<Separator noPadding />
</div>
@@ -122,6 +135,26 @@ const DocumentsSidebar = memo(
return { citedDocumentIds, citationOrder };
}, [idOfMessageToDisplay, selectedMessage?.packets.length]);
const observerRef = useRef<IntersectionObserver | null>(null);
const [isMoreStuck, setIsMoreStuck] = useState(false);
const moreSentinelRef = useCallback((node: HTMLDivElement | null) => {
observerRef.current?.disconnect();
observerRef.current = null;
if (!node) return;
const root = node.closest("#onyx-chat-sidebar");
if (!root) return;
const observer = new IntersectionObserver(
(entries) => setIsMoreStuck(!entries[0]?.isIntersecting),
{ root, threshold: 0 }
);
observer.observe(node);
observerRef.current = observer;
}, []);
// if these are missing for some reason, then nothing we can do. Just
// don't render.
// TODO: improve this display
@@ -167,7 +200,9 @@ const DocumentsSidebar = memo(
<div className="flex flex-col px-3 gap-6">
{hasCited && (
<div>
<Header onClose={closeSidebar}>Cited Sources</Header>
<Header isTop onClose={closeSidebar}>
Cited Sources
</Header>
<ChatDocumentDisplayWrapper>
{citedDocuments.map((document) => (
<ChatDocumentDisplay
@@ -186,7 +221,11 @@ const DocumentsSidebar = memo(
{hasOther && (
<div>
<Header onClose={closeSidebar}>
<div ref={moreSentinelRef} className="h-px" />
<Header
isTop={!hasCited || isMoreStuck}
onClose={!hasCited || isMoreStuck ? closeSidebar : undefined}
>
{citedDocuments.length > 0 ? "More" : "Found Sources"}
</Header>
<ChatDocumentDisplayWrapper>
@@ -207,7 +246,12 @@ const DocumentsSidebar = memo(
{humanFileDescriptors && humanFileDescriptors.length > 0 && (
<div>
<Header onClose={closeSidebar}>User Files</Header>
<Header
isTop={!hasCited && !hasOther}
onClose={!hasCited && !hasOther ? closeSidebar : undefined}
>
User Files
</Header>
<ChatDocumentDisplayWrapper>
{humanFileDescriptors.map((file) => (
<ChatDocumentDisplay

View File

@@ -649,9 +649,9 @@ const AppInputBar = React.memo(
<Disabled disabled>
<Button
icon={SvgMicrophone}
aria-label="Set up voice"
aria-label="Configure Voice Mode"
prominence="tertiary"
tooltip="Voice not configured. Set up in admin settings."
tooltip="Configure Voice Mode in Admin Settings."
/>
</Disabled>
))}

View File

@@ -143,7 +143,7 @@ const LLMStepInner = ({
rightIcon={SvgExternalLink}
href="/admin/configuration/llm"
>
View in Admin Panel
View in Admin Settings
</Button>
</Disabled>
}

View File

@@ -134,7 +134,7 @@ const collections = (
sidebarItem(ADMIN_PATHS.WEB_SEARCH),
sidebarItem(ADMIN_PATHS.IMAGE_GENERATION),
{
name: "Voice",
name: "Voice Mode",
icon: SvgAudio,
link: "/admin/configuration/voice",
},

View File

@@ -613,7 +613,7 @@ const MemoizedAppSidebarInner = memo(
icon={SvgSettings}
folded={folded}
>
{isAdmin ? "Admin Panel" : "Curator Panel"}
{isAdmin ? "Admin Settings" : "Curator Panel"}
</SidebarTab>
)}
<UserAvatarPopover