* remove legacy home page components, update home page to new layout * update PromptInput component styles to match new designs, make quick action buttons functional * home page chat creates new thread in last used workspace * fix slash commands and agent popup on home page * disable llm workspace selector action in home page * add drag and drop file support to home page * fix behavior of drag and drop on home page * handle pasting attachments in home page * update empty state of workspace chat to use new ui * update empty workspace ui to match home page design, fix flickering loading states * convert quick action buttons to component, add to empty state ws chat * fix hover state light mode in quick actions * add suggested messages subcomponent to empty ws/thread * adjust width, rounded edges of prompt input * only show quick actions for admin/manager role * fix hover states for quick actions and suggested messages component * make upload document quick action trigger parsed document upload * fix mic behavior in homepage, ws chat, ws thread chat * fix margin between prompt input and quick actions * Simplify message presets by removing heading input (#4915) * Remove heading input from message presets, merge legacy headings on edit * filter out empty messages from state after saving * mark form as dirty on input change * styling --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com> * convert SuggestedMessages to component, render SuggestedMessages in home page to target ws * fix broken handleMessageChange reference * add translations for QuickActions * lint * fix home page chat submission broken by PromptInput onChange removal * fix prompt input remount race condition, home page suggested message flicker * remove unused handleSendSuggestedMessage from ChatHistory * add greeting text to main-page translations, remove defaults * fix file deletion in parsed files menu on home page * add virtual thread sidebar state and workspace indicator on home page * show workspace llm selector on home page when workspace exists * show home page for all user roles with rbac quick actions * fix positioning of agent and slash command popups * remove workspace indicator from home page, match empty state spacing * Normalize translations for home page redesign (#4986) * normalize translations * update translations with DMR * accidentally changed es translation * normalize translations for main-page.greeting * update translations with DMR --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com> * update translations * create new workspace in native language Cleanup workspace page from empty state handling * update quick action show logic * fix send button --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
143 lines
4.8 KiB
JavaScript
143 lines
4.8 KiB
JavaScript
import { PaperclipHorizontal } from "@phosphor-icons/react";
|
|
import { Tooltip } from "react-tooltip";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useRef, useState, useEffect } from "react";
|
|
import { useParams } from "react-router-dom";
|
|
import Workspace from "@/models/workspace";
|
|
import {
|
|
ATTACHMENTS_PROCESSED_EVENT,
|
|
REMOVE_ATTACHMENT_EVENT,
|
|
} from "../../DnDWrapper";
|
|
import { useTheme } from "@/hooks/useTheme";
|
|
import ParsedFilesMenu from "./ParsedFilesMenu";
|
|
|
|
/**
|
|
* This is a simple proxy component that clicks on the DnD file uploader for the user.
|
|
* @returns
|
|
*/
|
|
export default function AttachItem({
|
|
workspaceSlug = null,
|
|
workspaceThreadSlug = null,
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const { theme } = useTheme();
|
|
const params = useParams();
|
|
const slug = workspaceSlug || params.slug;
|
|
const threadSlug = workspaceThreadSlug ?? params.threadSlug ?? null;
|
|
const tooltipRef = useRef(null);
|
|
const [isEmbedding, setIsEmbedding] = useState(false);
|
|
const [files, setFiles] = useState([]);
|
|
const [currentTokens, setCurrentTokens] = useState(0);
|
|
const [contextWindow, setContextWindow] = useState(Infinity);
|
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
const fetchFiles = () => {
|
|
if (!slug) return;
|
|
if (isEmbedding) return;
|
|
setIsLoading(true);
|
|
Workspace.getParsedFiles(slug, threadSlug)
|
|
.then(({ files, contextWindow, currentContextTokenCount }) => {
|
|
setFiles(files);
|
|
setShowTooltip(files.length > 0);
|
|
setContextWindow(contextWindow);
|
|
setCurrentTokens(currentContextTokenCount);
|
|
})
|
|
.finally(() => {
|
|
setIsLoading(false);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Handles the removal of an attachment from the parsed files
|
|
* and triggers a re-fetch of the parsed files.
|
|
* This function handles when the user clicks the X on an Attachment via the AttachmentManager
|
|
* so we need to sync the state in the ParsedFilesMenu picker here.
|
|
*/
|
|
async function handleRemoveAttachment(e) {
|
|
const { document } = e.detail;
|
|
await Workspace.deleteParsedFiles(slug, [document.id]);
|
|
fetchFiles();
|
|
}
|
|
|
|
/**
|
|
* Handles the click event for the attach item button.
|
|
* @param {MouseEvent} e - The click event.
|
|
* @returns {void}
|
|
*/
|
|
function handleClick(e) {
|
|
e?.target?.blur();
|
|
document?.getElementById("dnd-chat-file-uploader")?.click();
|
|
return;
|
|
}
|
|
|
|
useEffect(() => {
|
|
fetchFiles();
|
|
window.addEventListener(ATTACHMENTS_PROCESSED_EVENT, fetchFiles);
|
|
window.addEventListener(REMOVE_ATTACHMENT_EVENT, handleRemoveAttachment);
|
|
return () => {
|
|
window.removeEventListener(ATTACHMENTS_PROCESSED_EVENT, fetchFiles);
|
|
window.removeEventListener(
|
|
REMOVE_ATTACHMENT_EVENT,
|
|
handleRemoveAttachment
|
|
);
|
|
};
|
|
}, [slug, threadSlug]);
|
|
|
|
return (
|
|
<>
|
|
<button
|
|
id="attach-item-btn"
|
|
data-tooltip-id="tooltip-attach-item-btn"
|
|
aria-label={t("chat_window.attach_file")}
|
|
type="button"
|
|
onClick={handleClick}
|
|
onPointerEnter={fetchFiles}
|
|
className={`border-none relative flex justify-center items-center opacity-60 hover:opacity-100 light:opacity-100 light:hover:opacity-60 cursor-pointer`}
|
|
>
|
|
<div className="relative">
|
|
<PaperclipHorizontal
|
|
color="var(--theme-sidebar-footer-icon-fill)"
|
|
className="w-[20px] h-[20px] pointer-events-none text-white rotate-90 -scale-y-100"
|
|
/>
|
|
{files.length > 0 && (
|
|
<div className="absolute -top-2 right-[1%] bg-white text-black light:invert text-[8px] rounded-full px-1 flex items-center justify-center">
|
|
{files.length}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</button>
|
|
{showTooltip && (
|
|
<Tooltip
|
|
ref={tooltipRef}
|
|
id="tooltip-attach-item-btn"
|
|
place="top"
|
|
opacity={1}
|
|
clickable={!isEmbedding}
|
|
delayShow={300}
|
|
delayHide={isEmbedding ? 999999 : 800} // Prevent tooltip from hiding during embedding
|
|
arrowColor={
|
|
theme === "light"
|
|
? "var(--theme-modal-border)"
|
|
: "var(--theme-bg-primary)"
|
|
}
|
|
className="z-99 !w-[400px] !bg-theme-bg-primary !px-[5px] !rounded-lg !pointer-events-auto light:border-2 light:border-theme-modal-border"
|
|
>
|
|
<ParsedFilesMenu
|
|
onEmbeddingChange={setIsEmbedding}
|
|
tooltipRef={tooltipRef}
|
|
isLoading={isLoading}
|
|
files={files}
|
|
setFiles={setFiles}
|
|
currentTokens={currentTokens}
|
|
setCurrentTokens={setCurrentTokens}
|
|
contextWindow={contextWindow}
|
|
workspaceSlug={slug}
|
|
threadSlug={threadSlug}
|
|
/>
|
|
</Tooltip>
|
|
)}
|
|
</>
|
|
);
|
|
}
|