mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-17 04:14:29 +00:00
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:
1 parent
5aa4ec1b9f
commit
c4e8daf50e
21 files changed
+121
-86
No files matched your search
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -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,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 |
@@ -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')}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -384,7 +384,8 @@
|
|||||||
"title": "ソース",
|
"title": "ソース",
|
||||||
"text": "ソーステキスト",
|
"text": "ソーステキスト",
|
||||||
"link": "ソースリンク",
|
"link": "ソースリンク",
|
||||||
"view_more": "さらに{{count}}個のソース"
|
"view_more": "さらに{{count}}個のソース",
|
||||||
|
"noSourcesAvailable": "利用可能なソースがありません"
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"attach": "添付",
|
"attach": "添付",
|
||||||
|
|||||||
@@ -384,7 +384,8 @@
|
|||||||
"title": "Источники",
|
"title": "Источники",
|
||||||
"text": "Выберите ваши источники",
|
"text": "Выберите ваши источники",
|
||||||
"link": "Ссылка на источник",
|
"link": "Ссылка на источник",
|
||||||
"view_more": "ещё {{count}} источников"
|
"view_more": "ещё {{count}} источников",
|
||||||
|
"noSourcesAvailable": "Нет доступных источников"
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"attach": "Прикрепить",
|
"attach": "Прикрепить",
|
||||||
|
|||||||
@@ -384,7 +384,8 @@
|
|||||||
"title": "來源",
|
"title": "來源",
|
||||||
"text": "來源文字",
|
"text": "來源文字",
|
||||||
"link": "來源連結",
|
"link": "來源連結",
|
||||||
"view_more": "查看更多 {{count}} 個來源"
|
"view_more": "查看更多 {{count}} 個來源",
|
||||||
|
"noSourcesAvailable": "沒有可用的來源"
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"attach": "附件",
|
"attach": "附件",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
Reference in new issue
Block a user