Frontend audit: refinements (#2083)

* (fix:attachements) sep id for redux ops

* (fix:ui) popups, toast, share modal

* (feat:agentsPreview) stable preview, ui fixes

* (fix:ui) light theme icon, sleek scroll

---------

Co-authored-by: GH Action - Upstream Sync <action@github.com>
This commit is contained in:
Manish MadanandGH Action - Upstream Sync authored and GitHub committed 2025-10-22 12:12:05 +03:00
1 parent 5aa4ec1b9f
commit c4e8daf50e
21 files changed
+121 -86

No files matched your search

+16 -16
View File
@@ -109,18 +109,18 @@ export default function AgentPreview() {
} else setLastQueryReturnedErr(false); } else setLastQueryReturnedErr(false);
}, [queries]); }, [queries]);
return ( return (
<div> <div className="relative h-full w-full">
<div className="dark:bg-raisin-black flex h-full flex-col items-center justify-between gap-2 overflow-y-hidden"> <div className="scrollbar-thin absolute inset-0 bottom-[180px] overflow-hidden px-4 pt-4 [&>div>div]:!w-full [&>div>div]:!max-w-none">
<div className="h-[512px] w-full overflow-y-auto"> <ConversationMessages
<ConversationMessages handleQuestion={handleQuestion}
handleQuestion={handleQuestion} handleQuestionSubmission={handleQuestionSubmission}
handleQuestionSubmission={handleQuestionSubmission} queries={queries}
queries={queries} status={status}
status={status} showHeroOnEmpty={false}
showHeroOnEmpty={false} />
/> </div>
</div> <div className="absolute right-0 bottom-0 left-0 flex w-full flex-col gap-4 pb-2">
<div className="flex w-[95%] max-w-[1500px] flex-col items-center gap-4 pb-2 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12"> <div className="w-full px-4">
<MessageInput <MessageInput
onSubmit={(text) => handleQuestionSubmission(text)} onSubmit={(text) => handleQuestionSubmission(text)}
loading={status === 'loading'} loading={status === 'loading'}
@@ -128,11 +128,11 @@ export default function AgentPreview() {
showToolButton={selectedAgent ? false : true} showToolButton={selectedAgent ? false : true}
autoFocus={false} autoFocus={false}
/> />
<p className="text-gray-4000 dark:text-sonic-silver w-full self-center bg-transparent pt-2 text-center text-xs md:inline">
This is a preview of the agent. You can publish it to start using it
in conversations.
</p>
</div> </div>
<p className="text-gray-4000 dark:text-sonic-silver w-full bg-transparent text-center text-xs md:inline">
This is a preview of the agent. You can publish it to start using it
in conversations.
</p>
</div> </div>
</div> </div>
); );
+15 -13
View File
@@ -534,7 +534,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
setHasChanges(isChanged); setHasChanges(isChanged);
}, [agent, dispatch, effectiveMode, imageFile, jsonSchemaText]); }, [agent, dispatch, effectiveMode, imageFile, jsonSchemaText]);
return ( return (
<div className="p-4 md:p-12"> <div className="flex flex-col px-4 pt-4 pb-2 max-[1179px]:min-h-[100dvh] min-[1180px]:h-[100dvh] md:px-12 md:pt-12 md:pb-3">
<div className="flex items-center gap-3 px-4"> <div className="flex items-center gap-3 px-4">
<button <button
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]" className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
@@ -615,9 +615,9 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
</button> </button>
</div> </div>
</div> </div>
<div className="mt-5 flex w-full grid-cols-5 flex-col gap-10 min-[1180px]:grid min-[1180px]:gap-5"> <div className="mt-3 flex w-full flex-1 grid-cols-5 flex-col gap-10 rounded-[30px] bg-[#F6F6F6] p-5 max-[1179px]:overflow-visible min-[1180px]:grid min-[1180px]:gap-5 min-[1180px]:overflow-hidden dark:bg-[#383838]">
<div className="col-span-2 flex flex-col gap-5"> <div className="scrollbar-thin col-span-2 flex flex-col gap-5 max-[1179px]:overflow-visible min-[1180px]:max-h-full min-[1180px]:overflow-y-auto min-[1180px]:pr-3">
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]"> <div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Meta</h2> <h2 className="text-lg font-semibold">Meta</h2>
<input <input
className="border-silver text-jet dark:bg-raisin-black dark:text-bright-gray dark:placeholder:text-silver mt-3 w-full rounded-3xl border bg-white px-5 py-3 text-sm outline-hidden placeholder:text-gray-400 dark:border-[#7E7E7E]" className="border-silver text-jet dark:bg-raisin-black dark:text-bright-gray dark:placeholder:text-silver mt-3 w-full rounded-3xl border bg-white px-5 py-3 text-sm outline-hidden placeholder:text-gray-400 dark:border-[#7E7E7E]"
@@ -650,7 +650,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
/> />
</div> </div>
</div> </div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]"> <div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Source</h2> <h2 className="text-lg font-semibold">Source</h2>
<div className="mt-3"> <div className="mt-3">
<div className="flex flex-wrap items-center gap-1"> <div className="flex flex-wrap items-center gap-1">
@@ -744,7 +744,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
</div> </div>
</div> </div>
</div> </div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]"> <div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<div className="flex flex-wrap items-end gap-1"> <div className="flex flex-wrap items-end gap-1">
<div className="min-w-20 grow basis-full sm:basis-0"> <div className="min-w-20 grow basis-full sm:basis-0">
<Prompts <Prompts
@@ -781,7 +781,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
</button> </button>
</div> </div>
</div> </div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]"> <div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Tools</h2> <h2 className="text-lg font-semibold">Tools</h2>
<div className="mt-3 flex flex-wrap items-center gap-1"> <div className="mt-3 flex flex-wrap items-center gap-1">
<button <button
@@ -823,7 +823,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
/> />
</div> </div>
</div> </div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]"> <div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Agent type</h2> <h2 className="text-lg font-semibold">Agent type</h2>
<div className="mt-3"> <div className="mt-3">
<Dropdown <Dropdown
@@ -848,7 +848,7 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
/> />
</div> </div>
</div> </div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]"> <div className="dark:bg-raisin-black rounded-[30px] bg-white px-6 py-3 dark:text-[#E0E0E0]">
<button <button
onClick={() => onClick={() =>
setIsAdvancedSectionExpanded(!isAdvancedSectionExpanded) setIsAdvancedSectionExpanded(!isAdvancedSectionExpanded)
@@ -1032,9 +1032,11 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
)} )}
</div> </div>
</div> </div>
<div className="col-span-3 flex flex-col gap-3 rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]"> <div className="col-span-3 flex flex-col gap-2 max-[1179px]:h-auto max-[1179px]:px-0 max-[1179px]:py-0 min-[1180px]:h-full min-[1180px]:py-2 dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Preview</h2> <h2 className="text-lg font-semibold">Preview</h2>
<AgentPreviewArea /> <div className="flex-1 max-[1179px]:overflow-visible min-[1180px]:min-h-0 min-[1180px]:overflow-hidden">
<AgentPreviewArea />
</div>
</div> </div>
</div> </div>
<ConfirmationModal <ConfirmationModal
@@ -1071,9 +1073,9 @@ export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
function AgentPreviewArea() { function AgentPreviewArea() {
const selectedAgent = useSelector(selectSelectedAgent); const selectedAgent = useSelector(selectSelectedAgent);
return ( return (
<div className="dark:bg-raisin-black h-full w-full rounded-[30px] border border-[#F6F6F6] bg-white max-[1180px]:h-192 dark:border-[#7E7E7E]"> <div className="dark:bg-raisin-black w-full rounded-[30px] border border-[#F6F6F6] bg-white max-[1179px]:h-[600px] min-[1180px]:h-full dark:border-[#7E7E7E]">
{selectedAgent?.status === 'published' ? ( {selectedAgent?.status === 'published' ? (
<div className="flex h-full w-full flex-col justify-end overflow-auto rounded-[30px]"> <div className="flex h-full w-full flex-col overflow-hidden rounded-[30px]">
<AgentPreview /> <AgentPreview />
</div> </div>
) : ( ) : (
+9 -7
View File
@@ -177,13 +177,15 @@ export default function SharedAgent() {
/> />
</div> </div>
<div className="flex w-[95%] max-w-[1500px] flex-col items-center pb-2 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12"> <div className="flex w-[95%] max-w-[1500px] flex-col items-center pb-2 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12">
<MessageInput <div className="w-full px-2">
onSubmit={(text) => handleQuestionSubmission(text)} <MessageInput
loading={status === 'loading'} onSubmit={(text) => handleQuestionSubmission(text)}
showSourceButton={sharedAgent ? false : true} loading={status === 'loading'}
showToolButton={sharedAgent ? false : true} showSourceButton={sharedAgent ? false : true}
autoFocus={false} showToolButton={sharedAgent ? false : true}
/> autoFocus={false}
/>
</div>
<p className="text-gray-4000 dark:text-sonic-silver hidden w-screen self-center bg-transparent py-2 text-center text-xs md:inline md:w-full"> <p className="text-gray-4000 dark:text-sonic-silver hidden w-screen self-center bg-transparent py-2 text-center text-xs md:inline md:w-full">
{t('tagline')} {t('tagline')}
</p> </p>
+1 -1
View File
@@ -1,5 +1,5 @@
<svg width="113" height="124" viewBox="0 0 113 124" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="113" height="124" viewBox="0 0 113 124" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="55.5" cy="71" r="53" fill="#F1F1F1" fill-opacity="0.5"/> <circle cx="55.5" cy="71" r="53" fill="#E8E3F3" fill-opacity="0.6"/>
<rect x="-0.599797" y="0.654564" width="43.9445" height="61.5222" rx="4.39444" transform="matrix(-0.999048 0.0436194 0.0436194 0.999048 68.9873 43.3176)" fill="#EEEEEE" stroke="#999999" stroke-width="1.25556"/> <rect x="-0.599797" y="0.654564" width="43.9445" height="61.5222" rx="4.39444" transform="matrix(-0.999048 0.0436194 0.0436194 0.999048 68.9873 43.3176)" fill="#EEEEEE" stroke="#999999" stroke-width="1.25556"/>
<rect x="0.704349" y="-0.540466" width="46.4556" height="64.0333" rx="5.65" transform="matrix(-0.991445 -0.130526 -0.130526 0.991445 96.3673 40.893)" fill="#FAFAFA" stroke="#999999" stroke-width="1.25556"/> <rect x="0.704349" y="-0.540466" width="46.4556" height="64.0333" rx="5.65" transform="matrix(-0.991445 -0.130526 -0.130526 0.991445 96.3673 40.893)" fill="#FAFAFA" stroke="#999999" stroke-width="1.25556"/>
<path d="M94.3796 45.7849C94.7417 43.0349 92.8059 40.5122 90.0559 40.1501L55.2011 35.5614C52.4511 35.1994 49.9284 37.1352 49.5663 39.8851L48.3372 49.2212L93.1505 55.121L94.3796 45.7849Z" fill="#EEEEEE"/> <path d="M94.3796 45.7849C94.7417 43.0349 92.8059 40.5122 90.0559 40.1501L55.2011 35.5614C52.4511 35.1994 49.9284 37.1352 49.5663 39.8851L48.3372 49.2212L93.1505 55.121L94.3796 45.7849Z" fill="#EEEEEE"/>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

+14 -16
View File
@@ -91,8 +91,10 @@ export default function MessageInput({
const apiHost = import.meta.env.VITE_API_HOST; const apiHost = import.meta.env.VITE_API_HOST;
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
const uniqueId = crypto.randomUUID();
const newAttachment = { const newAttachment = {
id: uniqueId,
fileName: file.name, fileName: file.name,
progress: 0, progress: 0,
status: 'uploading' as const, status: 'uploading' as const,
@@ -106,7 +108,7 @@ export default function MessageInput({
const progress = Math.round((event.loaded / event.total) * 100); const progress = Math.round((event.loaded / event.total) * 100);
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: newAttachment.taskId, id: uniqueId,
updates: { progress }, updates: { progress },
}), }),
); );
@@ -119,7 +121,7 @@ export default function MessageInput({
if (response.task_id) { if (response.task_id) {
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: newAttachment.taskId, id: uniqueId,
updates: { updates: {
taskId: response.task_id, taskId: response.task_id,
status: 'processing', status: 'processing',
@@ -131,7 +133,7 @@ export default function MessageInput({
} else { } else {
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: newAttachment.taskId, id: uniqueId,
updates: { status: 'failed' }, updates: { status: 'failed' },
}), }),
); );
@@ -141,7 +143,7 @@ export default function MessageInput({
xhr.onerror = () => { xhr.onerror = () => {
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: newAttachment.taskId, id: uniqueId,
updates: { status: 'failed' }, updates: { status: 'failed' },
}), }),
); );
@@ -167,7 +169,7 @@ export default function MessageInput({
if (data.status === 'SUCCESS') { if (data.status === 'SUCCESS') {
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: attachment.taskId!, id: attachment.id,
updates: { updates: {
status: 'completed', status: 'completed',
progress: 100, progress: 100,
@@ -179,14 +181,14 @@ export default function MessageInput({
} else if (data.status === 'FAILURE') { } else if (data.status === 'FAILURE') {
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: attachment.taskId!, id: attachment.id,
updates: { status: 'failed' }, updates: { status: 'failed' },
}), }),
); );
} else if (data.status === 'PROGRESS' && data.result?.current) { } else if (data.status === 'PROGRESS' && data.result?.current) {
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: attachment.taskId!, id: attachment.id,
updates: { progress: data.result.current }, updates: { progress: data.result.current },
}), }),
); );
@@ -195,7 +197,7 @@ export default function MessageInput({
.catch(() => { .catch(() => {
dispatch( dispatch(
updateAttachment({ updateAttachment({
taskId: attachment.taskId!, id: attachment.id,
updates: { status: 'failed' }, updates: { status: 'failed' },
}), }),
); );
@@ -260,12 +262,12 @@ export default function MessageInput({
}; };
return ( return (
<div className="mx-2 flex w-full flex-col"> <div className="flex w-full flex-col">
<div className="border-dark-gray bg-lotion dark:border-grey relative flex w-full flex-col rounded-[23px] border dark:bg-transparent"> <div className="border-dark-gray bg-lotion dark:border-grey relative flex w-full flex-col rounded-[23px] border dark:bg-transparent">
<div className="flex flex-wrap gap-1.5 px-2 py-2 sm:gap-2 sm:px-3"> <div className="flex flex-wrap gap-1.5 px-2 py-2 sm:gap-2 sm:px-3">
{attachments.map((attachment, index) => ( {attachments.map((attachment) => (
<div <div
key={index} key={attachment.id}
className={`group dark:text-bright-gray relative flex items-center rounded-xl bg-[#EFF3F4] px-2 py-1 text-[12px] text-[#5D5D5D] sm:px-3 sm:py-1.5 sm:text-[14px] dark:bg-[#393B3D] ${ className={`group dark:text-bright-gray relative flex items-center rounded-xl bg-[#EFF3F4] px-2 py-1 text-[12px] text-[#5D5D5D] sm:px-3 sm:py-1.5 sm:text-[14px] dark:bg-[#393B3D] ${
attachment.status !== 'completed' ? 'opacity-70' : 'opacity-100' attachment.status !== 'completed' ? 'opacity-70' : 'opacity-100'
}`} }`}
@@ -327,11 +329,7 @@ export default function MessageInput({
<button <button
className="ml-1.5 flex items-center justify-center rounded-full p-1" className="ml-1.5 flex items-center justify-center rounded-full p-1"
onClick={() => { onClick={() => {
if (attachment.id) { dispatch(removeAttachment(attachment.id));
dispatch(removeAttachment(attachment.id));
} else if (attachment.taskId) {
dispatch(removeAttachment(attachment.taskId));
}
}} }}
aria-label={t('conversation.attachments.remove')} aria-label={t('conversation.attachments.remove')}
> >
+1 -1
View File
@@ -33,7 +33,7 @@ export default function Sidebar({
return ( return (
<div ref={sidebarRef} className="h-vh relative"> <div ref={sidebarRef} className="h-vh relative">
<div <div
className={`dark:bg-chinese-black fixed top-0 right-0 z-50 h-full w-72 transform bg-white shadow-xl transition-all duration-300 sm:w-96 ${ className={`dark:bg-chinese-black fixed top-0 right-0 z-50 h-full w-64 transform bg-white shadow-xl transition-all duration-300 sm:w-80 ${
isOpen ? 'translate-x-[10px]' : 'translate-x-full' isOpen ? 'translate-x-[10px]' : 'translate-x-full'
} border-l border-[#9ca3af]/10`} } border-l border-[#9ca3af]/10`}
> >
+5 -2
View File
@@ -1,4 +1,5 @@
import React, { useRef, useEffect, useState, useLayoutEffect } from 'react'; import React, { useRef, useEffect, useState, useLayoutEffect } from 'react';
import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Doc } from '../models/misc'; import { Doc } from '../models/misc';
@@ -107,7 +108,7 @@ export default function SourcesPopup({
onClose(); onClose();
}; };
return ( const popupContent = (
<div <div
ref={popupRef} ref={popupRef}
className="bg-lotion dark:bg-charleston-green-2 fixed z-50 flex flex-col rounded-xl shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]" className="bg-lotion dark:bg-charleston-green-2 fixed z-50 flex flex-col rounded-xl shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
@@ -218,7 +219,7 @@ export default function SourcesPopup({
</> </>
) : ( ) : (
<div className="dark:text-bright-gray p-4 text-center text-gray-500 dark:text-[14px]"> <div className="dark:text-bright-gray p-4 text-center text-gray-500 dark:text-[14px]">
{t('noSourcesAvailable')} {t('conversation.sources.noSourcesAvailable')}
</div> </div>
)} )}
</div> </div>
@@ -245,4 +246,6 @@ export default function SourcesPopup({
</div> </div>
</div> </div>
); );
return createPortal(popupContent, document.body);
} }
+5 -2
View File
@@ -1,4 +1,5 @@
import React, { useEffect, useRef, useState, useLayoutEffect } from 'react'; import React, { useEffect, useRef, useState, useLayoutEffect } from 'react';
import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { selectToken } from '../preferences/preferenceSlice'; import { selectToken } from '../preferences/preferenceSlice';
@@ -133,10 +134,10 @@ export default function ToolsPopup({
tool.displayName.toLowerCase().includes(searchTerm.toLowerCase()), tool.displayName.toLowerCase().includes(searchTerm.toLowerCase()),
); );
return ( const popupContent = (
<div <div
ref={popupRef} ref={popupRef}
className="border-light-silver bg-lotion dark:border-dim-gray dark:bg-charleston-green-2 fixed z-9999 rounded-lg border shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]" className="border-light-silver bg-lotion dark:border-dim-gray dark:bg-charleston-green-2 fixed z-50 rounded-lg border shadow-[0px_9px_46px_8px_#0000001F,0px_24px_38px_3px_#00000024,0px_11px_15px_-7px_#00000033]"
style={{ style={{
top: popupPosition.showAbove ? popupPosition.top : undefined, top: popupPosition.showAbove ? popupPosition.top : undefined,
bottom: popupPosition.showAbove bottom: popupPosition.showAbove
@@ -242,4 +243,6 @@ export default function ToolsPopup({
</div> </div>
</div> </div>
); );
return createPortal(popupContent, document.body);
} }
+4 -1
View File
@@ -44,7 +44,10 @@ export default function UploadToast() {
}; };
return ( return (
<div className="fixed right-4 bottom-4 z-50 flex max-w-md flex-col gap-2"> <div
className="fixed right-4 bottom-4 z-50 flex max-w-md flex-col gap-2"
onMouseDown={(e) => e.stopPropagation()}
>
{uploadTasks {uploadTasks
.filter((task) => !task.dismissed) .filter((task) => !task.dismissed)
.map((task) => { .map((task) => {
+1 -1
View File
@@ -224,7 +224,7 @@ export default function Conversation() {
<div className="bg-opacity-0 z-3 flex h-auto w-full max-w-[1300px] flex-col items-end self-center rounded-2xl py-1 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12"> <div className="bg-opacity-0 z-3 flex h-auto w-full max-w-[1300px] flex-col items-end self-center rounded-2xl py-1 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12">
<div <div
{...getRootProps()} {...getRootProps()}
className="flex w-full items-center rounded-[40px]" className="flex w-full items-center rounded-[40px] px-2"
> >
<label htmlFor="file-upload" className="sr-only"> <label htmlFor="file-upload" className="sr-only">
{t('modals.uploadDoc.label')} {t('modals.uploadDoc.label')}
@@ -635,7 +635,7 @@ function AllSources(sources: AllSourcesProps) {
<p className="text-left text-xl">{`${sources.sources.length} ${t('conversation.sources.title')}`}</p> <p className="text-left text-xl">{`${sources.sources.length} ${t('conversation.sources.title')}`}</p>
<div className="mx-1 mt-2 h-[0.8px] w-full rounded-full bg-[#C4C4C4]/40 lg:w-[95%]"></div> <div className="mx-1 mt-2 h-[0.8px] w-full rounded-full bg-[#C4C4C4]/40 lg:w-[95%]"></div>
</div> </div>
<div className="mt-6 flex h-[90%] w-60 flex-col items-center gap-4 overflow-y-auto sm:w-80"> <div className="scrollbar-thin mt-6 flex h-[90%] w-52 flex-col gap-4 overflow-y-auto pr-3 sm:w-64">
{sources.sources.map((source, index) => { {sources.sources.map((source, index) => {
const isExternalSource = source.link && source.link !== 'local'; const isExternalSource = source.link && source.link !== 'local';
return ( return (
@@ -161,14 +161,16 @@ export const SharedConversation = () => {
/> />
<div className="flex w-full max-w-[1200px] flex-col items-center gap-4 pb-2 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12"> <div className="flex w-full max-w-[1200px] flex-col items-center gap-4 pb-2 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12">
{apiKey ? ( {apiKey ? (
<MessageInput <div className="w-full px-2">
onSubmit={(text) => { <MessageInput
handleQuestionSubmission(text); onSubmit={(text) => {
}} handleQuestionSubmission(text);
loading={status === 'loading'} }}
showSourceButton={false} loading={status === 'loading'}
showToolButton={false} showSourceButton={false}
/> showToolButton={false}
/>
</div>
) : ( ) : (
<button <button
onClick={() => navigate('/')} onClick={() => navigate('/')}
+20 -4
View File
@@ -118,18 +118,34 @@ layer(base);
background: transparent; background: transparent;
} }
/* Light theme scrollbar */
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background: rgba(156, 163, 175, 0.5); background: rgba(215, 215, 215, 1);
border-radius: 3px; border-radius: 3px;
} }
&::-webkit-scrollbar-thumb:hover { &::-webkit-scrollbar-thumb:hover {
background: rgba(156, 163, 175, 0.7); background: rgba(195, 195, 195, 1);
} }
/* For Firefox */ /* Dark theme scrollbar */
.dark &::-webkit-scrollbar-thumb {
background: rgba(77, 78, 88, 1);
border-radius: 3px;
}
.dark &::-webkit-scrollbar-thumb:hover {
background: rgba(97, 98, 108, 1);
}
/* For Firefox - Light theme */
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: rgba(156, 163, 175, 0.5) transparent; scrollbar-color: rgba(215, 215, 215, 1) transparent;
/* For Firefox - Dark theme */
.dark & {
scrollbar-color: rgba(77, 78, 88, 1) transparent;
}
} }
@utility table-default { @utility table-default {
+2 -1
View File
@@ -421,7 +421,8 @@
"title": "Sources", "title": "Sources",
"text": "Choose Your Sources", "text": "Choose Your Sources",
"link": "Source link", "link": "Source link",
"view_more": "{{count}} more sources" "view_more": "{{count}} more sources",
"noSourcesAvailable": "No sources available"
}, },
"attachments": { "attachments": {
"attach": "Attach", "attach": "Attach",
+2 -1
View File
@@ -384,7 +384,8 @@
"title": "Fuentes", "title": "Fuentes",
"link": "Enlace fuente", "link": "Enlace fuente",
"view_more": "Ver {{count}} más fuentes", "view_more": "Ver {{count}} más fuentes",
"text": "Elegir tus fuentes" "text": "Elegir tus fuentes",
"noSourcesAvailable": "No hay fuentes disponibles"
}, },
"attachments": { "attachments": {
"attach": "Adjuntar", "attach": "Adjuntar",
+2 -1
View File
@@ -384,7 +384,8 @@
"title": "ソース", "title": "ソース",
"text": "ソーステキスト", "text": "ソーステキスト",
"link": "ソースリンク", "link": "ソースリンク",
"view_more": "さらに{{count}}個のソース" "view_more": "さらに{{count}}個のソース",
"noSourcesAvailable": "利用可能なソースがありません"
}, },
"attachments": { "attachments": {
"attach": "添付", "attach": "添付",
+2 -1
View File
@@ -384,7 +384,8 @@
"title": "Источники", "title": "Источники",
"text": "Выберите ваши источники", "text": "Выберите ваши источники",
"link": "Ссылка на источник", "link": "Ссылка на источник",
"view_more": "ещё {{count}} источников" "view_more": "ещё {{count}} источников",
"noSourcesAvailable": "Нет доступных источников"
}, },
"attachments": { "attachments": {
"attach": "Прикрепить", "attach": "Прикрепить",
+2 -1
View File
@@ -384,7 +384,8 @@
"title": "來源", "title": "來源",
"text": "來源文字", "text": "來源文字",
"link": "來源連結", "link": "來源連結",
"view_more": "查看更多 {{count}} 個來源" "view_more": "查看更多 {{count}} 個來源",
"noSourcesAvailable": "沒有可用的來源"
}, },
"attachments": { "attachments": {
"attach": "附件", "attach": "附件",
+2 -1
View File
@@ -384,7 +384,8 @@
"title": "来源", "title": "来源",
"text": "来源文本", "text": "来源文本",
"link": "来源链接", "link": "来源链接",
"view_more": "还有{{count}}个来源" "view_more": "还有{{count}}个来源",
"noSourcesAvailable": "没有可用的来源"
}, },
"attachments": { "attachments": {
"attach": "附件", "attach": "附件",
@@ -103,8 +103,8 @@ export const ShareConversationModal = ({
}; };
return ( return (
<WrapperModal close={close}> <WrapperModal close={close} contentClassName="!overflow-visible">
<div className="flex max-h-[80vh] w-[600px] max-w-[80vw] flex-col gap-2 overflow-y-auto"> <div className="flex w-[600px] max-w-[80vw] flex-col gap-2">
<h2 className="text-eerie-black dark:text-chinese-white text-xl font-medium"> <h2 className="text-eerie-black dark:text-chinese-white text-xl font-medium">
{t('modals.shareConv.label')} {t('modals.shareConv.label')}
</h2> </h2>
+5 -5
View File
@@ -2,11 +2,11 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState } from '../store'; import { RootState } from '../store';
export interface Attachment { export interface Attachment {
id: string; // Unique identifier for the attachment (required for state management)
fileName: string; fileName: string;
progress: number; progress: number;
status: 'uploading' | 'processing' | 'completed' | 'failed'; status: 'uploading' | 'processing' | 'completed' | 'failed';
taskId: string; taskId: string; // Server-assigned task ID (used for API calls)
id?: string;
token_count?: number; token_count?: number;
} }
@@ -47,12 +47,12 @@ export const uploadSlice = createSlice({
updateAttachment: ( updateAttachment: (
state, state,
action: PayloadAction<{ action: PayloadAction<{
taskId: string; id: string;
updates: Partial<Attachment>; updates: Partial<Attachment>;
}>, }>,
) => { ) => {
const index = state.attachments.findIndex( const index = state.attachments.findIndex(
(att) => att.taskId === action.payload.taskId, (att) => att.id === action.payload.id,
); );
if (index !== -1) { if (index !== -1) {
state.attachments[index] = { state.attachments[index] = {
@@ -63,7 +63,7 @@ export const uploadSlice = createSlice({
}, },
removeAttachment: (state, action: PayloadAction<string>) => { removeAttachment: (state, action: PayloadAction<string>) => {
state.attachments = state.attachments.filter( state.attachments = state.attachments.filter(
(att) => att.taskId !== action.payload && att.id !== action.payload, (att) => att.id !== action.payload,
); );
}, },
clearAttachments: (state) => { clearAttachments: (state) => {