Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions frontend/src/components/AttachmentGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ export const AttachmentGallery: React.FC<AttachmentGalleryProps> = ({
const downloadCurrentImage = async () => {
if (images[currentImageIndex]) {
const attachment = images[currentImageIndex]
if (!attachment.url) {
console.error("Download failed: attachment URL is missing.");
return;
}
try {
const response = await authFetch(
`/api/v1/attachments/${attachment.fileId}`,
attachment.url ?? "",
{
credentials: "include",
},
Expand Down Expand Up @@ -82,7 +86,7 @@ export const AttachmentGallery: React.FC<AttachmentGalleryProps> = ({
<div className="flex justify-end ml-auto w-fit">
<div className="relative rounded-md overflow-hidden ml-auto">
<img
src={`/api/v1/attachments/${images[0].fileId}`}
src={images[0].url}
alt={images[0].fileName}
className="rounded-md shadow border border-gray-200 block ml-auto cursor-pointer hover:opacity-80 transition-opacity max-w-[50%] h-auto"
onClick={() => handleImageGalleryOpen(0)}
Expand All @@ -98,7 +102,7 @@ export const AttachmentGallery: React.FC<AttachmentGalleryProps> = ({
onClick={() => handleImageGalleryOpen(index)}
>
<img
src={`/api/v1/attachments/${image.fileId}/thumbnail`}
src={image.thumbnailUrl}
alt={image.fileName}
className="w-28 h-28 object-cover rounded-md shadow-sm border border-gray-200"
/>
Expand Down Expand Up @@ -175,7 +179,7 @@ export const AttachmentGallery: React.FC<AttachmentGalleryProps> = ({

<div className="relative h-[90vh] flex items-center justify-center bg-black">
<img
src={`/api/v1/attachments/${images[currentImageIndex]?.fileId}`}
src={images[currentImageIndex]?.url}
alt={images[currentImageIndex]?.fileName}
className="max-w-full max-h-full object-contain"
/>
Expand Down Expand Up @@ -217,7 +221,7 @@ export const AttachmentGallery: React.FC<AttachmentGalleryProps> = ({
onClick={() => setCurrentImageIndex(index)}
>
<img
src={`/api/v1/attachments/${image.fileId}/thumbnail`}
src={image.thumbnailUrl}
alt={image.fileName}
className="w-full h-full object-cover rounded"
/>
Expand Down
9 changes: 3 additions & 6 deletions frontend/src/components/AttachmentPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ export const AttachmentPreview: React.FC<AttachmentPreviewProps> = ({
const [imageError, setImageError] = useState(false)

const isImage = attachment.isImage && !imageError
const thumbnailUrl = attachment.thumbnailPath
? `/api/v1/attachments/${attachment.fileId}/thumbnail`
: null

const handleImageView = () => {
if (isImage) {
Expand All @@ -54,7 +51,7 @@ export const AttachmentPreview: React.FC<AttachmentPreviewProps> = ({
>
{/* Thumbnail or Icon */}
<div className="flex-shrink-0">
{isImage && thumbnailUrl ? (
{isImage && attachment.thumbnailUrl ? (
<div
className="w-12 h-12 rounded-md overflow-hidden cursor-pointer hover:opacity-80 transition-opacity"
onClick={handleImageView}
Expand All @@ -63,7 +60,7 @@ export const AttachmentPreview: React.FC<AttachmentPreviewProps> = ({
aria-label={`Preview ${attachment.fileName}`}
>
<img
src={thumbnailUrl}
src={attachment.thumbnailUrl}
alt={attachment.fileName}
className="w-full h-full object-cover"
onError={handleImageError}
Expand Down Expand Up @@ -112,7 +109,7 @@ export const AttachmentPreview: React.FC<AttachmentPreviewProps> = ({
</DialogHeader>
<div className="px-6 pb-6">
<img
src={`/api/v1/attachments/${attachment.fileId}`}
src={attachment.url}
alt={attachment.fileName}
className="w-full h-auto max-h-[70vh] object-contain rounded-lg"
onError={handleImageError}
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/components/CitationLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface Citation {
url: string
title: string
docId: string
app: string
itemId?: string
clId?: string
}
Expand Down Expand Up @@ -65,7 +66,9 @@ export const createCitationLink =
}
}

if (citation && citation.clId && citation.itemId) {
const isAttachmentLink = citation && citation.app === "attachment"

if (citation && ((citation.clId && citation.itemId) || isAttachmentLink)) {
return (
<TooltipProvider delayDuration={200}>
<Tooltip open={isTooltipOpen} onOpenChange={setIsTooltipOpen}>
Expand Down Expand Up @@ -101,7 +104,7 @@ export const createCitationLink =
e.preventDefault()
e.stopPropagation()
if (onCitationClick) {
onCitationClick(citation)
onCitationClick(citation, chunkIndex)
}
setIsTooltipOpen(false)
}}
Expand Down Expand Up @@ -141,7 +144,7 @@ export const createCitationLink =
{citation.title.split("/").pop() || "Untitled Document"}
</div>
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 leading-tight truncate">
{citation.title.replace(/[^/]*$/, "") || "No file name"}
{citation.title.replace(/[^/]*$/, "") || (isAttachmentLink ? "attachment" : "No file name")}
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/CitationPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const CitationPreview: React.FC<CitationPreviewProps> = ({
const { highlightText, clearHighlights, scrollToMatch } = useScopedFind(
containerRef,
{
documentId: citation?.itemId,
documentId: citation?.itemId ?? citation?.docId ?? "",
},
)

Expand Down Expand Up @@ -129,7 +129,7 @@ const CitationPreview: React.FC<CitationPreviewProps> = ({

useEffect(() => {
clearHighlights()
}, [citation?.itemId, clearHighlights])
}, [citation?.itemId, citation?.docId, clearHighlights])

const getFileExtension = (mimeType: string, filename: string): string => {
if (mimeType === "application/pdf") {
Expand Down
20 changes: 19 additions & 1 deletion frontend/src/components/GroupFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Apps,
AttachmentEntity,
CalendarEntity,
DataSourceEntity,
DriveEntity,
Expand Down Expand Up @@ -158,7 +159,24 @@ export const getName = (app: Apps, entity: Entity): string => {
return "OutLook-Attachments"
}
return "Outlook"
} else {
} else if (app === Apps.Attachment) {
if(entity === AttachmentEntity.Docs){
return "Attachments Docs"
} else if(entity === AttachmentEntity.PDF){
return "Attachments Pdfs"
} else if(entity === AttachmentEntity.PPT){
return "Attachments PPTs"
} else if(entity === AttachmentEntity.Sheets){
return "Attachments Sheets"
} else if(entity === AttachmentEntity.Image){
return "Attachments Images"
} else if(entity === AttachmentEntity.Text) {
return "Attachments Text"
} else {
return "Attachments File"
}
}
else {
throw new Error(`Invalid app ${app} and entity ${entity}`)
}
}
Expand Down
20 changes: 12 additions & 8 deletions frontend/src/routes/_authenticated/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1206,13 +1206,14 @@ export const ChatPage = ({
// Handle chunk index changes from CitationPreview
const handleChunkIndexChange = useCallback(
async (newChunkIndex: number | null, documentId: string, docId: string) => {
if (!documentId) {
console.error("handleChunkIndexChange called without documentId")
return
const citationId = selectedCitation?.itemId ?? selectedCitation?.docId;
if (citationId && !documentId) {
console.error("handleChunkIndexChange called without documentId");
return;
}

if (selectedCitation?.itemId !== documentId) {
return
if (citationId && citationId !== documentId) {
return;
}

if (newChunkIndex === null) {
Expand Down Expand Up @@ -1244,7 +1245,7 @@ export const ChatPage = ({
const chunkContent = await chunkContentResponse.json()

// Ensure we are still on the same document before mutating UI
if (selectedCitation?.itemId !== documentId) {
if ((selectedCitation?.itemId && selectedCitation?.itemId !== documentId) || (!selectedCitation?.itemId && selectedCitation?.docId && selectedCitation?.docId !== documentId)) {
return
}

Expand Down Expand Up @@ -1287,7 +1288,7 @@ export const ChatPage = ({
if (selectedCitation && isDocumentLoaded) {
handleChunkIndexChange(
selectedChunkIndex,
selectedCitation?.itemId ?? "",
selectedCitation?.itemId ?? ((selectedCitation?.app === "attachment") ? (selectedCitation?.docId ?? "") : ""),
selectedCitation?.docId ?? "",
)
}
Expand All @@ -1301,7 +1302,10 @@ export const ChatPage = ({
// Handler for citation clicks - moved before conditional returns
const handleCitationClick = useCallback(
(citation: Citation, chunkIndex?: number, fromSources: boolean = false) => {
if (!citation || !citation.clId || !citation.itemId) {
const isRegularCitation = citation?.clId && citation?.itemId;
const isAttachment = citation?.app === 'attachment';

if (!citation || (!isRegularCitation && !isAttachment)) {
// For citations without clId or itemId, open as regular link
if (citation.url) {
window.open(citation.url, "_blank", "noopener,noreferrer")
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/utils/chatUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ export const generateUUID = () => crypto.randomUUID()

export const textToCitationIndex = /\[(\d+)\]/g
export const textToImageCitationIndex = /(?<!K)\[(\d+_\d+)\]/g
export const textToKbItemCitationIndex = /K\[(\d+_\d+)\]/g
export const textToChunkCitationIndex = /K\[(\d+_\d+)\]/g

// Function to clean citation numbers from response text
export const cleanCitationsFromResponse = (text: string): string => {
// Clean both types of citations and trim any extra whitespace
return text
.replace(textToCitationIndex, "")
.replace(textToImageCitationIndex, "")
.replace(textToKbItemCitationIndex, "")
.replace(textToChunkCitationIndex, "")
.replace(/[ \t]+/g, " ")
.trim()
}
Expand Down Expand Up @@ -44,7 +44,7 @@ export const processMessage = (
// Handle KB citations
// Case 1: K[docId_chunkIndex] format (during streaming, before backend processing)
// Case 2: [N_chunkIndex] format (after backend processing or from DB)
text = text.replace(textToKbItemCitationIndex, (_, citationKey) => {
text = text.replace(textToChunkCitationIndex, (_, citationKey) => {
const parts = citationKey.split("_")
const originalIndex = parseInt(parts[0], 10)
const chunkIndex = parseInt(parts[1], 10)
Expand Down
Loading