mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-10-11 05:36:03 +02:00
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:
@@ -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">
|
||||||
|
@@ -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;
|
||||||
|
@@ -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,
|
||||||
|
@@ -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>
|
||||||
|
@@ -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>
|
||||||
|
@@ -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}
|
||||||
|
@@ -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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,7 @@ export const IconImageSelection = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function IconImageUpload({
|
export function IconImageUpload({
|
||||||
selectedFile,
|
selectedFile,
|
||||||
updateFile,
|
updateFile,
|
||||||
|
@@ -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>
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user