Make chat page layout cleaner + fix updating assistant images (#1973)

* ux updates for clarity
- [x] 'folders' -> 'chat folders'
- [x] sidebar to bottom left and smaller
- [x] Sidebar -> smaller logo
- [x] Align things properly
- [x] Expliti Pin: immediate + "Pin / Unpin"
- [x] Logo size smaller
- [x] Align things properly
- [x] Optionally fix gradient in sidebar
- [x] Upload logo to existing assistants

* remove unneeded logs

* run pretty

* actually run pretty!

* fix web file type

* fix very minor typo

* clean type for buildPersonaAPIBody

* fix span formatting

* HUGE ui change
This commit is contained in:
pablodanswer
2024-07-29 20:44:35 -07:00
committed by GitHub
parent fb6695a983
commit 7932e764d6
10 changed files with 70 additions and 42 deletions

View File

@@ -571,7 +571,6 @@ export function AssistantEditor({
)} )}
</div> </div>
</div> </div>
<div className="mb-6"> <div className="mb-6">
<div className="flex gap-x-2 items-center"> <div className="flex gap-x-2 items-center">
<div className="block font-medium text-base"> <div className="block font-medium text-base">

View File

@@ -105,7 +105,7 @@ function updatePrompt({
function buildPersonaAPIBody( function buildPersonaAPIBody(
creationRequest: PersonaCreationRequest | PersonaUpdateRequest, creationRequest: PersonaCreationRequest | PersonaUpdateRequest,
promptId: number, promptId: number,
uploaded_image_id?: string // uploaded_image_id: string | null
) { ) {
const { const {
name, name,
@@ -190,7 +190,7 @@ export async function createPersona(
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify( body: JSON.stringify(
buildPersonaAPIBody(personaCreationRequest, promptId, fileId!) buildPersonaAPIBody(personaCreationRequest, promptId, fileId)
), ),
}) })
: null; : null;
@@ -225,6 +225,14 @@ export async function updatePersona(
promptId = promptResponse.ok ? (await promptResponse.json()).id : null; promptId = promptResponse.ok ? (await promptResponse.json()).id : null;
} }
let fileId = null;
if (personaUpdateRequest.uploaded_image) {
fileId = await uploadFile(personaUpdateRequest.uploaded_image);
if (!fileId) {
return [promptResponse, null];
}
}
const updatePersonaResponse = const updatePersonaResponse =
promptResponse.ok && promptId promptResponse.ok && promptId
? await fetch(`/api/persona/${id}`, { ? await fetch(`/api/persona/${id}`, {
@@ -233,7 +241,7 @@ export async function updatePersona(
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify( body: JSON.stringify(
buildPersonaAPIBody(personaUpdateRequest, promptId) buildPersonaAPIBody(personaUpdateRequest, promptId, fileId)
), ),
}) })
: null; : null;

View File

@@ -183,7 +183,7 @@ export default function AddConnector({
const { message, isSuccess, response } = await submitConnector<any>( const { message, isSuccess, response } = await submitConnector<any>(
{ {
connector_specific_config: values, connector_specific_config: values,
input_type: "poll", input_type: connector == "web" ? "load_state" : "poll", // single case
name: name, name: name,
source: connector, source: connector,
refresh_freq: (refreshFreq || defaultRefresh) * 60, refresh_freq: (refreshFreq || defaultRefresh) * 60,

View File

@@ -90,7 +90,7 @@ export function ChatSessionDisplay({
/> />
)} )}
<Link <Link
className="flex my-1 relative" className="flex my-1 group relative"
key={chatSession.id} key={chatSession.id}
href={ href={
search search
@@ -126,10 +126,15 @@ export function ChatSessionDisplay({
className="-my-px px-1 mr-2 w-full rounded" className="-my-px px-1 mr-2 w-full rounded"
/> />
) : ( ) : (
<p className="break-all overflow-hidden whitespace-nowrap mr-3 text-emphasis"> <p className="break-all overflow-hidden whitespace-nowrap w-full mr-3 relative">
{chatName || `Chat ${chatSession.id}`} {chatName || `Chat ${chatSession.id}`}
<span
className={`absolute right-0 top-0 h-full w-8 bg-gradient-to-r from-transparent
${isSelected ? "to-background-200" : " to-background-100 group-hover:to-background-200"} `}
/>
</p> </p>
)} )}
{isSelected && {isSelected &&
(isRenamingChat ? ( (isRenamingChat ? (
<div className="ml-auto my-auto flex"> <div className="ml-auto my-auto flex">
@@ -199,12 +204,6 @@ export function ChatSessionDisplay({
</div> </div>
))} ))}
</div> </div>
{isSelected && !isRenamingChat && !delayedSkipGradient && (
<div className="absolute bottom-0 right-0 top-0 bg-gradient-to-l to-transparent from-hover w-20 from-60% rounded" />
)}
{!isSelected && !delayedSkipGradient && (
<div className="absolute bottom-0 right-0 top-0 bg-gradient-to-l to-transparent from-background-100 w-8 from-0% rounded" />
)}
</> </>
</BasicSelectable> </BasicSelectable>
</Link> </Link>

View File

@@ -101,7 +101,7 @@ export const HistorySidebar = forwardRef<HTMLDivElement, HistorySidebarProps>(
transition-transform`} transition-transform`}
> >
<div className="max-w-full ml-3 mr-3 mt-2 flex flex gap-x-1 items-center my-auto text-text-700 text-xl"> <div className="max-w-full ml-3 mr-3 mt-2 flex flex gap-x-1 items-center my-auto text-text-700 text-xl">
<div className="mr-1 mb-auto h-6 w-6"> <div className="mr-1 invisible mb-auto h-6 w-6">
<Logo height={24} width={24} /> <Logo height={24} width={24} />
</div> </div>
@@ -120,8 +120,11 @@ export const HistorySidebar = forwardRef<HTMLDivElement, HistorySidebarProps>(
)} )}
</div> </div>
{toggleSidebar && ( {toggleSidebar && (
<Tooltip delayDuration={1000} content={`${commandSymbol}E show`}> <Tooltip
<button className="mb-auto ml-auto" onClick={toggleSidebar}> delayDuration={0}
content={toggled ? `Unpin sidebar` : "Pin sidebar"}
>
<button className="my-auto ml-auto" onClick={toggleSidebar}>
{!toggled ? <RightToLineIcon /> : <LefToLineIcon />} {!toggled ? <RightToLineIcon /> : <LefToLineIcon />}
</button> </button>
</Tooltip> </Tooltip>

View File

@@ -62,7 +62,7 @@ export function PagesTab({
{folders && folders.length > 0 && ( {folders && folders.length > 0 && (
<div className="py-2 border-b border-border"> <div className="py-2 border-b border-border">
<div className="text-xs text-subtle flex pb-0.5 mb-1.5 mt-2 font-bold"> <div className="text-xs text-subtle flex pb-0.5 mb-1.5 mt-2 font-bold">
Folders Chat Folders
</div> </div>
<FolderList <FolderList
folders={folders} folders={folders}

View File

@@ -5,6 +5,7 @@ import { Logo } from "@/components/Logo";
import { SettingsContext } from "@/components/settings/SettingsProvider"; import { SettingsContext } from "@/components/settings/SettingsProvider";
import { NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED } from "@/lib/constants"; import { NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED } from "@/lib/constants";
import { useContext } from "react"; import { useContext } from "react";
import { FiSidebar } from "react-icons/fi";
export default function FixedLogo() { export default function FixedLogo() {
const combinedSettings = useContext(SettingsContext); const combinedSettings = useContext(SettingsContext);
@@ -12,10 +13,11 @@ export default function FixedLogo() {
const enterpriseSettings = combinedSettings?.enterpriseSettings; const enterpriseSettings = combinedSettings?.enterpriseSettings;
return ( return (
<>
<div className="absolute flex z-40 left-2.5 top-2"> <div className="absolute flex z-40 left-2.5 top-2">
<div className="max-w-[200px] flex gap-x-1 my-auto"> <div className="max-w-[200px] flex items-center gap-x-1 my-auto">
<div className="flex-none invisible mb-auto"> <div className="flex-none my-auto">
<Logo /> <Logo height={24} width={24} />
</div> </div>
<div className=""> <div className="">
{enterpriseSettings && enterpriseSettings.application_name ? ( {enterpriseSettings && enterpriseSettings.application_name ? (
@@ -31,5 +33,9 @@ export default function FixedLogo() {
</div> </div>
</div> </div>
</div> </div>
<div className="absolute left-2.5 bottom-4">
<FiSidebar />
</div>
</>
); );
} }

View File

@@ -41,6 +41,7 @@ export const IconImageSelection = ({
</div> </div>
); );
}; };
export function IconImageUpload({ export function IconImageUpload({
selectedFile, selectedFile,
updateFile, updateFile,

View File

@@ -5,7 +5,10 @@ import { FiShare2, FiSidebar } from "react-icons/fi";
import { SetStateAction, useContext, useEffect } from "react"; import { SetStateAction, useContext, useEffect } from "react";
import { Logo } from "../Logo"; import { Logo } from "../Logo";
import { ChatIcon, NewChatIcon, PlusCircleIcon } from "../icons/icons"; import { ChatIcon, NewChatIcon, PlusCircleIcon } from "../icons/icons";
import { NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA } from "@/lib/constants"; import {
NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED,
NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA,
} from "@/lib/constants";
import { ChatSession } from "@/app/chat/interfaces"; import { ChatSession } from "@/app/chat/interfaces";
import { HeaderTitle } from "../header/Header"; import { HeaderTitle } from "../header/Header";
import { Tooltip } from "../tooltip/Tooltip"; import { Tooltip } from "../tooltip/Tooltip";
@@ -60,13 +63,20 @@ export default function FunctionalHeader({
<div className="pb-6 left-0 sticky top-0 z-10 w-full relative flex"> <div className="pb-6 left-0 sticky top-0 z-10 w-full relative flex">
<div className="mt-2 mx-4 text-text-700 flex w-full"> <div className="mt-2 mx-4 text-text-700 flex w-full">
<div className="absolute z-[100] my-auto flex items-center text-xl font-bold"> <div className="absolute z-[100] my-auto flex items-center text-xl font-bold">
<div className="pt-[2px] mb-auto"> <div className="pt-[2px] invisible mb-auto">
<FiSidebar size={20} /> <FiSidebar size={20} />
</div> </div>
<div className="break-words inline-block w-fit ml-2 text-text-700 text-xl"> <div className="invisible break-words inline-block w-fit ml-2 text-text-700 text-xl">
<div className="max-w-[200px]"> <div className="max-w-[200px]">
{enterpriseSettings && enterpriseSettings.application_name ? ( {enterpriseSettings && enterpriseSettings.application_name ? (
<HeaderTitle>{enterpriseSettings.application_name}</HeaderTitle> <div>
<HeaderTitle>
{enterpriseSettings.application_name}
</HeaderTitle>
{!NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED && (
<p className="text-xs text-subtle">Powered by Danswer</p>
)}
</div>
) : ( ) : (
<HeaderTitle>Danswer</HeaderTitle> <HeaderTitle>Danswer</HeaderTitle>
)} )}
@@ -76,7 +86,7 @@ export default function FunctionalHeader({
{page == "chat" && ( {page == "chat" && (
<Tooltip delayDuration={1000} content={`${commandSymbol}U`}> <Tooltip delayDuration={1000} content={`${commandSymbol}U`}>
<Link <Link
className="mb-auto pt-[2px]" className="my-auto"
href={ href={
`/${page}` + `/${page}` +
(NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA && (NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA &&
@@ -86,7 +96,7 @@ export default function FunctionalHeader({
} }
> >
<div className="cursor-pointer ml-2 flex-none text-text-700 hover:text-text-600 transition-colors duration-300"> <div className="cursor-pointer ml-2 flex-none text-text-700 hover:text-text-600 transition-colors duration-300">
<NewChatIcon size={20} className="" /> <NewChatIcon size={20} />
</div> </div>
</Link> </Link>
</Tooltip> </Tooltip>

View File

@@ -12,13 +12,15 @@ import { NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED } from "@/lib/constan
import { pageType } from "@/app/chat/sessionSidebar/types"; import { pageType } from "@/app/chat/sessionSidebar/types";
export function HeaderTitle({ children }: { children: JSX.Element | string }) { export function HeaderTitle({ children }: { children: JSX.Element | string }) {
const isString = typeof children === "string";
const textSize = isString && children.length > 10 ? "text-xl" : "text-2xl";
return ( return (
<h1 className="flex text-2xl text-strong leading-none font-bold"> <h1 className={`flex ${textSize} text-strong leading-none font-bold`}>
{children} {children}
</h1> </h1>
); );
} }
interface HeaderProps { interface HeaderProps {
user: User | null; user: User | null;
page?: pageType; page?: pageType;