diff --git a/backend/alembic/versions/9aadf32dfeb4_add_user_files.py b/backend/alembic/versions/9aadf32dfeb4_add_user_files.py
index 941ce7f6b..b20addc9c 100644
--- a/backend/alembic/versions/9aadf32dfeb4_add_user_files.py
+++ b/backend/alembic/versions/9aadf32dfeb4_add_user_files.py
@@ -1,7 +1,7 @@
"""add user files
Revision ID: 9aadf32dfeb4
-Revises: df46c75b714e
+Revises: 3781a5eb12cb
Create Date: 2025-01-26 16:08:21.551022
"""
@@ -12,7 +12,7 @@ import datetime
# revision identifiers, used by Alembic.
revision = "9aadf32dfeb4"
-down_revision = "df46c75b714e"
+down_revision = "3781a5eb12cb"
branch_labels = None
depends_on = None
@@ -42,6 +42,7 @@ def upgrade() -> None:
sa.ForeignKey("user_folder.id"),
nullable=True,
),
+ sa.Column("link_url", sa.String(), nullable=True),
sa.Column("token_count", sa.Integer(), nullable=True),
sa.Column("file_type", sa.String(), nullable=True),
sa.Column("file_id", sa.String(length=255), nullable=False),
diff --git a/backend/onyx/db/models.py b/backend/onyx/db/models.py
index 70b66ff53..999e0082b 100644
--- a/backend/onyx/db/models.py
+++ b/backend/onyx/db/models.py
@@ -2430,6 +2430,7 @@ class UserFile(Base):
cc_pair: Mapped["ConnectorCredentialPair"] = relationship(
"ConnectorCredentialPair", back_populates="user_file"
)
+ link_url: Mapped[str | None] = mapped_column(String, nullable=True)
"""
diff --git a/backend/onyx/db/user_documents.py b/backend/onyx/db/user_documents.py
index 3cffd9b13..17174b42b 100644
--- a/backend/onyx/db/user_documents.py
+++ b/backend/onyx/db/user_documents.py
@@ -38,6 +38,7 @@ def create_user_files(
folder_id: int | None,
user: User | None,
db_session: Session,
+ link_url: str | None = None,
) -> list[UserFile]:
upload_response = upload_files(files, db_session)
user_files = []
@@ -50,6 +51,7 @@ def create_user_files(
document_id="USER_FILE_CONNECTOR__" + file_path,
name=file.filename,
token_count=None,
+ link_url=link_url,
)
db_session.add(new_file)
user_files.append(new_file)
diff --git a/backend/onyx/indexing/indexing_pipeline.py b/backend/onyx/indexing/indexing_pipeline.py
index af73c48fc..b3849bb01 100644
--- a/backend/onyx/indexing/indexing_pipeline.py
+++ b/backend/onyx/indexing/indexing_pipeline.py
@@ -12,9 +12,6 @@ from onyx.configs.app_configs import MAX_DOCUMENT_CHARS
from onyx.configs.constants import DEFAULT_BOOST
from onyx.configs.llm_configs import get_image_extraction_and_analysis_enabled
from onyx.configs.model_configs import USE_INFORMATION_CONTENT_CLASSIFICATION
-from onyx.configs.constants import (
- DEFAULT_BOOST,
-)
from onyx.connectors.cross_connector_utils.miscellaneous_utils import (
get_experts_stores_representations,
)
@@ -65,10 +62,10 @@ from onyx.indexing.models import IndexChunk
from onyx.indexing.models import UpdatableChunkData
from onyx.indexing.vector_db_insertion import write_chunks_to_vector_db_with_backoff
from onyx.llm.factory import get_default_llm_with_vision
+from onyx.llm.factory import get_default_llms
from onyx.natural_language_processing.search_nlp_models import (
InformationContentClassificationModel,
)
-from onyx.llm.factory import get_default_llms
from onyx.natural_language_processing.utils import get_tokenizer
from onyx.utils.logger import setup_logger
from onyx.utils.timing import log_function_time
@@ -836,6 +833,8 @@ def index_doc_batch(
chunk_data=updatable_chunk_data, db_session=db_session
)
+ # Pause user file ccpairs
+
db_session.commit()
result = IndexingPipelineResult(
diff --git a/backend/onyx/main.py b/backend/onyx/main.py
index 1efbd306d..dbaff5497 100644
--- a/backend/onyx/main.py
+++ b/backend/onyx/main.py
@@ -211,7 +211,9 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
logger.notice("Generative AI Q&A disabled")
# fill up Postgres connection pools
+ print("Warming up connections")
await warm_up_connections()
+ print("Connections warmed up")
if not MULTI_TENANT:
# We cache this at the beginning so there is no delay in the first telemetry
@@ -219,10 +221,12 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
get_or_generate_uuid()
# If we are multi-tenant, we need to only set up initial public tables
+ print("Setting up onyx")
with Session(engine) as db_session:
setup_onyx(db_session, POSTGRES_DEFAULT_SCHEMA)
else:
setup_multitenant_onyx()
+ print("onyz set up")
if not MULTI_TENANT:
# don't emit a metric for every pod rollover/restart
diff --git a/backend/onyx/server/user_documents/api.py b/backend/onyx/server/user_documents/api.py
index 424330988..53aaf65a2 100644
--- a/backend/onyx/server/user_documents/api.py
+++ b/backend/onyx/server/user_documents/api.py
@@ -25,6 +25,7 @@ from onyx.db.connector_credential_pair import add_credential_to_connector
from onyx.db.credentials import create_credential
from onyx.db.engine import get_session
from onyx.db.enums import AccessType
+from onyx.db.models import ConnectorCredentialPair
from onyx.db.models import User
from onyx.db.models import UserFile
from onyx.db.models import UserFolder
@@ -363,11 +364,13 @@ def create_file_from_link(
soup = BeautifulSoup(content, "html.parser")
parsed_html = web_html_cleanup(soup, mintlify_cleanup_enabled=False)
- file_name = f"{parsed_html.title or 'Untitled'}.txt"
+ file_name = f"{parsed_html.title or 'Untitled'}"
file_content = parsed_html.cleaned_text.encode()
file = UploadFile(filename=file_name, file=io.BytesIO(file_content))
- user_files = create_user_files([file], request.folder_id, user, db_session)
+ user_files = create_user_files(
+ [file], request.folder_id, user, db_session, link_url=request.url
+ )
# Create connector and credential (same as in upload_user_files)
for user_file in user_files:
@@ -448,6 +451,61 @@ def get_files_token_estimate(
return {"total_tokens": total_tokens}
+class ReindexFileRequest(BaseModel):
+ file_id: int
+
+
+@router.post("/user/file/reindex")
+def reindex_file(
+ request: ReindexFileRequest,
+ user: User = Depends(current_user),
+ db_session: Session = Depends(get_session),
+) -> MessageResponse:
+ user_id = user.id if user else None
+ user_file_to_reindex = (
+ db_session.query(UserFile)
+ .filter(UserFile.id == request.file_id, UserFile.user_id == user_id)
+ .first()
+ )
+
+ if not user_file_to_reindex:
+ raise HTTPException(status_code=404, detail="File not found")
+
+ if not user_file_to_reindex.cc_pair_id:
+ raise HTTPException(
+ status_code=400,
+ detail="File does not have an associated connector-credential pair",
+ )
+
+ # Get the connector id from the cc_pair
+ cc_pair = (
+ db_session.query(ConnectorCredentialPair)
+ .filter_by(id=user_file_to_reindex.cc_pair_id)
+ .first()
+ )
+ if not cc_pair:
+ raise HTTPException(
+ status_code=404, detail="Associated connector-credential pair not found"
+ )
+
+ # Trigger immediate reindexing with highest priority
+ tenant_id = get_current_tenant_id()
+ try:
+ trigger_indexing_for_cc_pair(
+ [], cc_pair.connector_id, True, tenant_id, db_session, is_user_file=True
+ )
+ return MessageResponse(
+ message="File reindexing has been triggered successfully"
+ )
+ except Exception as e:
+ logger.error(
+ f"Error triggering reindexing for file {request.file_id}: {str(e)}"
+ )
+ raise HTTPException(
+ status_code=500, detail=f"Failed to trigger reindexing: {str(e)}"
+ )
+
+
class BulkCleanupRequest(BaseModel):
folder_id: int
days_older_than: int | None = None
diff --git a/backend/onyx/server/user_documents/models.py b/backend/onyx/server/user_documents/models.py
index 11d84e036..207191192 100644
--- a/backend/onyx/server/user_documents/models.py
+++ b/backend/onyx/server/user_documents/models.py
@@ -19,6 +19,8 @@ class UserFileSnapshot(BaseModel):
assistant_ids: List[int] = [] # List of assistant IDs
token_count: int | None
indexed: bool
+ link_url: str | None
+ failed: bool | None
@classmethod
def from_model(cls, model: UserFile) -> "UserFileSnapshot":
@@ -32,9 +34,12 @@ class UserFileSnapshot(BaseModel):
created_at=model.created_at,
assistant_ids=[assistant.id for assistant in model.assistants],
token_count=model.token_count,
+ failed=len(model.cc_pair.index_attempts) > 0
+ and model.cc_pair.last_successful_index_time is None,
indexed=model.cc_pair.last_successful_index_time is not None
if model.cc_pair
else False,
+ link_url=model.link_url,
)
diff --git a/backend/onyx/setup.py b/backend/onyx/setup.py
index b1d2a4c04..03239ca28 100644
--- a/backend/onyx/setup.py
+++ b/backend/onyx/setup.py
@@ -74,12 +74,15 @@ def setup_onyx(
The Tenant Service calls the tenants/create endpoint which runs this.
"""
+ print("checking and performing index swap")
check_and_perform_index_swap(db_session=db_session)
+ print("getting active search settings")
active_search_settings = get_active_search_settings(db_session)
search_settings = active_search_settings.primary
secondary_search_settings = active_search_settings.secondary
+ print("getting current search settings")
# search_settings = get_current_search_settings(db_session)
# multipass_config_1 = get_multipass_config(search_settings)
@@ -91,6 +94,7 @@ def setup_onyx(
# Break bad state for thrashing indexes
if secondary_search_settings and DISABLE_INDEX_UPDATE_ON_SWAP:
+ print("expiring index attempts")
expire_index_attempts(
search_settings_id=search_settings.id, db_session=db_session
)
@@ -99,6 +103,7 @@ def setup_onyx(
resync_cc_pair(cc_pair, db_session=db_session)
# Expire all old embedding models indexing attempts, technically redundant
+ print("cancelling indexing attempts past model")
cancel_indexing_attempts_past_model(db_session)
logger.notice(f'Using Embedding model: "{search_settings.model_name}"')
diff --git a/web/src/app/chat/ChatPage.tsx b/web/src/app/chat/ChatPage.tsx
index b6f503a78..ca080ef02 100644
--- a/web/src/app/chat/ChatPage.tsx
+++ b/web/src/app/chat/ChatPage.tsx
@@ -189,6 +189,7 @@ export function ChatPage({
removeSelectedFolder,
clearSelectedItems,
folders: userFolders,
+ files: allUserFiles,
uploadFile,
removeSelectedFile,
currentMessageFiles,
@@ -2769,11 +2770,25 @@ export function ChatPage({
? messageHistory[i + 1]
: undefined;
- const userFiles = previousMessage?.files.filter(
- (file) =>
- file.type == ChatFileType.USER_KNOWLEDGE
+ const attachedFileDescriptors =
+ previousMessage?.files.filter(
+ (file) =>
+ file.type == ChatFileType.USER_KNOWLEDGE
+ );
+ const userFiles = allUserFiles?.filter((file) =>
+ attachedFileDescriptors?.some(
+ (descriptor) =>
+ descriptor.id === file.file_id
+ )
);
-
+ console.log("alluser files");
+ console.log(allUserFiles);
+ console.log(
+ "current attached file descriptors"
+ );
+ console.log(attachedFileDescriptors);
+ console.log("user files");
+ console.log(userFiles);
return (
(
return () => clearTimeout(timer);
}, [selectedDocuments]);
+ const { files: allUserFiles } = useDocumentsContext();
- const userFiles = humanMessage?.files.filter(
+ const humanFileDescriptors = humanMessage?.files.filter(
(file) => file.type == ChatFileType.USER_KNOWLEDGE
);
+ const userFiles = allUserFiles?.filter((file) =>
+ humanFileDescriptors?.some((descriptor) => descriptor.id === file.file_id)
+ );
const selectedDocumentIds =
selectedDocuments?.map((document) => document.document_id) || [];
@@ -127,7 +132,12 @@ export const DocumentResults = forwardRef(
+ setPresentingDocument({
+ document_id: file.document_id,
+ semantic_identifier: file.file_id || null,
+ })
+ }
/>
))}
diff --git a/web/src/app/chat/interfaces.ts b/web/src/app/chat/interfaces.ts
index 4a75c6dcd..a236290c9 100644
--- a/web/src/app/chat/interfaces.ts
+++ b/web/src/app/chat/interfaces.ts
@@ -50,6 +50,10 @@ export interface FileDescriptor {
isUploading?: boolean;
}
+export interface FileDescriptorWithHighlights extends FileDescriptor {
+ match_highlights: string[];
+}
+
export interface LLMRelevanceFilterPacket {
relevant_chunk_indices: number[];
}
diff --git a/web/src/app/chat/message/MemoizedTextComponents.tsx b/web/src/app/chat/message/MemoizedTextComponents.tsx
index 7a440964d..167215004 100644
--- a/web/src/app/chat/message/MemoizedTextComponents.tsx
+++ b/web/src/app/chat/message/MemoizedTextComponents.tsx
@@ -10,12 +10,14 @@ import { SourceIcon } from "@/components/SourceIcon";
import { WebResultIcon } from "@/components/WebResultIcon";
import { SubQuestionDetail } from "../interfaces";
import { ValidSources } from "@/lib/types";
+import { FileResponse } from "../my-documents/DocumentsContext";
export const MemoizedAnchor = memo(
({
docs,
subQuestions,
openQuestion,
+ userFiles,
href,
updatePresentingDocument,
children,
@@ -23,6 +25,7 @@ export const MemoizedAnchor = memo(
subQuestions?: SubQuestionDetail[];
openQuestion?: (question: SubQuestionDetail) => void;
docs?: OnyxDocument[] | null;
+ userFiles?: FileResponse[] | null;
updatePresentingDocument: (doc: OnyxDocument) => void;
href?: string;
children: React.ReactNode;
@@ -31,8 +34,14 @@ export const MemoizedAnchor = memo(
if (value?.startsWith("[") && value?.endsWith("]")) {
const match = value.match(/\[(D|Q)?(\d+)\]/);
if (match) {
- const isSubQuestion = match[1] === "Q";
- if (!isSubQuestion) {
+ const isUserFileCitation = userFiles?.length && userFiles.length > 0;
+ if (isUserFileCitation) {
+ const index = parseInt(match[2], 10) - 1;
+ const associatedUserFile = userFiles?.[index];
+ if (!associatedUserFile) {
+ return {children};
+ }
+ } else if (!isUserFileCitation) {
const index = parseInt(match[2], 10) - 1;
const associatedDoc = docs?.[index];
if (!associatedDoc) {
diff --git a/web/src/app/chat/message/Messages.tsx b/web/src/app/chat/message/Messages.tsx
index d8e57f51f..e75fa3f75 100644
--- a/web/src/app/chat/message/Messages.tsx
+++ b/web/src/app/chat/message/Messages.tsx
@@ -73,6 +73,7 @@ import rehypeKatex from "rehype-katex";
import "katex/dist/katex.min.css";
import { copyAll, handleCopy } from "./copyingUtils";
import { transformLinkUri } from "@/lib/utils";
+import { FileResponse } from "../my-documents/DocumentsContext";
const TOOLS_WITH_CUSTOM_HANDLING = [
SEARCH_TOOL_NAME,
@@ -164,6 +165,46 @@ function FileDisplay({
);
}
+function FileResponseDisplay({
+ files,
+ alignBubble,
+ setPresentingDocument,
+}: {
+ files: FileResponse[];
+ alignBubble?: boolean;
+ setPresentingDocument: (document: MinimalOnyxDocument) => void;
+}) {
+ if (!files || files.length === 0) {
+ return null;
+ }
+
+ return (
+
+
+ {files.map((file) => {
+ return (
+
+
+ setPresentingDocument({
+ document_id: file.document_id,
+ semantic_identifier: file.name || file.document_id,
+ })
+ }
+ />
+
+ );
+ })}
+
+
+ );
+}
+
export const AIMessage = ({
userKnowledgeFiles = [],
regenerate,
@@ -195,7 +236,7 @@ export const AIMessage = ({
documentSidebarVisible,
removePadding,
}: {
- userKnowledgeFiles?: FileDescriptor[];
+ userKnowledgeFiles?: FileResponse[];
index?: number;
shared?: boolean;
isActive?: boolean;
@@ -323,6 +364,7 @@ export const AIMessage = ({
{props.children}
@@ -522,8 +564,11 @@ export const AIMessage = ({
+ setPresentingDocument({
+ document_id: doc.document_id,
+ semantic_identifier: doc.document_id,
+ })
}
/>
))}
@@ -555,15 +600,19 @@ export const AIMessage = ({
userKnowledgeFiles.length > 0 &&
userKnowledgeFiles
.slice(0, 2)
- .map((file: FileDescriptor, ind: number) => (
+ .map((file: FileResponse, ind: number) => (
+ setPresentingDocument({
+ document_id: file.document_id,
+ semantic_identifier: file.name,
+ })
}
/>
))}
+
{userKnowledgeFiles.length > 2 && (
)}
- {content || userKnowledgeFiles || files ? (
+
+ {content || files ? (
<>
{typeof content === "string" ? (
diff --git a/web/src/app/chat/message/SearchSummary.tsx b/web/src/app/chat/message/SearchSummary.tsx
index 9c15410aa..cb94c31bd 100644
--- a/web/src/app/chat/message/SearchSummary.tsx
+++ b/web/src/app/chat/message/SearchSummary.tsx
@@ -16,6 +16,7 @@ import { ValidSources } from "@/lib/types";
import { useEffect, useRef, useState } from "react";
import { FiBook, FiCheck, FiEdit2, FiSearch, FiX } from "react-icons/fi";
import { FileDescriptor } from "../interfaces";
+import { FileResponse } from "../my-documents/DocumentsContext";
export function ShowHideDocsButton({
messageId,
@@ -250,7 +251,7 @@ export function SearchSummary({
export function UserKnowledgeFiles({
userKnowledgeFiles,
}: {
- userKnowledgeFiles: FileDescriptor[];
+ userKnowledgeFiles: FileResponse[];
}): JSX.Element {
if (!userKnowledgeFiles || userKnowledgeFiles.length === 0) {
return <>>;
diff --git a/web/src/app/chat/message/SourcesDisplay.tsx b/web/src/app/chat/message/SourcesDisplay.tsx
index 3fe728096..3e7cdc74d 100644
--- a/web/src/app/chat/message/SourcesDisplay.tsx
+++ b/web/src/app/chat/message/SourcesDisplay.tsx
@@ -6,8 +6,9 @@ import { buildDocumentSummaryDisplay } from "@/components/search/DocumentDisplay
import { ValidSources } from "@/lib/types";
import { FiFileText } from "react-icons/fi";
import { FileDescriptor } from "../interfaces";
-import { getFileIconFromFileName } from "@/lib/assistantIconUtils";
+import { getFileIconFromFileNameAndLink } from "@/lib/assistantIconUtils";
import { truncateString } from "@/lib/utils";
+import { FileResponse } from "../my-documents/DocumentsContext";
interface SourcesDisplayProps {
documents: OnyxDocument[];
@@ -68,14 +69,21 @@ export const SourceCard: React.FC<{
};
export const FileSourceCard: React.FC<{
- document: FileDescriptor;
- setPresentingDocument: (document: MinimalOnyxDocument) => void;
+ document: FileResponse;
+ setPresentingDocument: (document: FileResponse) => void;
}> = ({ document, setPresentingDocument }) => {
+ const openDocument = () => {
+ if (document.link_url) {
+ window.open(document.link_url, "_blank");
+ } else {
+ setPresentingDocument(document as any);
+ }
+ };
const fileName = document.name || document.id;
return (
- {getFileIconFromFileName(fileName)}
-
+ {getFileIconFromFileNameAndLink(document.name, document.link_url)}
- Document
+ {truncateString(document.name, 45)}
@@ -106,14 +113,19 @@ export const FileSourceCard: React.FC<{
};
export const FileSourceCardInResults: React.FC<{
- document: FileDescriptor;
- setPresentingDocument: (document: MinimalOnyxDocument) => void;
+ document: FileResponse;
+ setPresentingDocument: (document: FileResponse) => void;
}> = ({ document, setPresentingDocument }) => {
- const fileName = document.name || document.id;
-
+ const openDocument = () => {
+ if (document.link_url) {
+ window.open(document.link_url, "_blank");
+ } else {
+ setPresentingDocument(document as any);
+ }
+ };
return (
diff --git a/web/src/app/chat/my-documents/DocumentsContext.tsx b/web/src/app/chat/my-documents/DocumentsContext.tsx
index 90613dc3c..b84b59697 100644
--- a/web/src/app/chat/my-documents/DocumentsContext.tsx
+++ b/web/src/app/chat/my-documents/DocumentsContext.tsx
@@ -34,7 +34,10 @@ export type FileResponse = {
assistant_ids?: number[];
indexed?: boolean;
created_at?: string;
+ file_id?: string;
file_type?: string;
+ link_url?: string | null;
+ failed?: boolean;
};
export interface FileUploadResponse {
@@ -43,6 +46,7 @@ export interface FileUploadResponse {
export interface DocumentsContextType {
folders: FolderResponse[];
+ files: FileResponse[];
currentFolder: number | null;
presentingDocument: MinimalOnyxDocument | null;
searchQuery: string;
@@ -486,6 +490,7 @@ export const DocumentsProvider: React.FC = ({
);
const value: DocumentsContextType = {
+ files: folders.map((folder) => folder.files).flat(),
folders,
currentFolder,
presentingDocument,
diff --git a/web/src/app/chat/my-documents/[id]/components/DocumentList.tsx b/web/src/app/chat/my-documents/[id]/components/DocumentList.tsx
index 06c6040e7..bca130313 100644
--- a/web/src/app/chat/my-documents/[id]/components/DocumentList.tsx
+++ b/web/src/app/chat/my-documents/[id]/components/DocumentList.tsx
@@ -116,6 +116,13 @@ export const DocumentList: React.FC = ({
}) => {
const [presentingDocument, setPresentingDocument] =
useState(null);
+ const openDocument = (file: FileResponse) => {
+ if (file.link_url) {
+ window.open(file.link_url, "_blank");
+ } else {
+ setPresentingDocument(file);
+ }
+ };
const [uploadingFiles, setUploadingFiles] = useState([]);
const [completedFiles, setCompletedFiles] = useState([]);
const [refreshInterval, setRefreshInterval] = useState(
@@ -499,8 +506,9 @@ export const DocumentList: React.FC = ({
onDownload={onDownload}
onMove={onMove}
folders={folders}
- onSelect={() => setPresentingDocument(file)}
+ onSelect={() => openDocument(file)}
isIndexed={file.indexed || false}
+ failed={file.failed || false}
/>
)}
diff --git a/web/src/app/chat/my-documents/[id]/components/upload/FileUploadSection.tsx b/web/src/app/chat/my-documents/[id]/components/upload/FileUploadSection.tsx
index 3fb527f9e..befa49e9c 100644
--- a/web/src/app/chat/my-documents/[id]/components/upload/FileUploadSection.tsx
+++ b/web/src/app/chat/my-documents/[id]/components/upload/FileUploadSection.tsx
@@ -535,7 +535,7 @@ export const FileUploadSection: React.FC = ({
{/* Content area - different for each mode but with consistent spacing */}
-
+
Promise
;
folders: FolderResponse[];
isIndexed: boolean;
+ failed: boolean;
}
export const FileListItem: React.FC = ({
@@ -52,6 +62,7 @@ export const FileListItem: React.FC = ({
onMove,
folders,
isIndexed,
+ failed,
}) => {
const [showMoveOptions, setShowMoveOptions] = useState(false);
const [indexingStatus, setIndexingStatus] = useState(null);
@@ -82,6 +93,72 @@ export const FileListItem: React.FC = ({
onMove(file.id, targetFolderId);
setShowMoveOptions(false);
};
+ const FailureWithPopover = () => {
+ return (
+
+ e.stopPropagation()} asChild>
+
+
+
+
+
+
+
+
+ Indexing failed.
+
+ You can attempt a reindex to continue using this file, or delete
+ the file.
+
+
+
+
+
+
+
+
+
+ );
+ };
return (
= ({
{isSelected !== undefined && (
)}
- {getFileIconFromFileName(file.name)}
+ {file.failed ? (
+
+ ) : (
+ getFileIconFromFileNameAndLink(file.name, file.link_url)
+ )}
{file.name.length > 50 ? (
diff --git a/web/src/app/chat/my-documents/components/FilePicker.tsx b/web/src/app/chat/my-documents/components/FilePicker.tsx
index a76877028..a240067a9 100644
--- a/web/src/app/chat/my-documents/components/FilePicker.tsx
+++ b/web/src/app/chat/my-documents/components/FilePicker.tsx
@@ -53,7 +53,7 @@ import { getFormattedDateTime } from "@/lib/dateUtils";
import { FileUploadSection } from "../[id]/components/upload/FileUploadSection";
import { truncateString } from "@/lib/utils";
import { MinimalOnyxDocument } from "@/lib/search/interfaces";
-import { getFileIconFromFileName } from "@/lib/assistantIconUtils";
+import { getFileIconFromFileNameAndLink } from "@/lib/assistantIconUtils";
import { TokenDisplay } from "@/components/TokenDisplay";
// Define a type for uploading files that includes progress
@@ -114,8 +114,6 @@ const DraggableItem: React.FC<{
{...listeners}
className="flex group w-full items-center"
>
- {/* // className="flex group items-center" */}
-
- {getFileIconFromFileName(file.name)}
+ {getFileIconFromFileNameAndLink(file.name, file.link_url)}
{file.name.length > 34 ? (
@@ -460,10 +458,14 @@ export const FilePickerModal: React.FC = ({
}
};
const handleFileClick = (file: FileResponse) => {
- setPresentingDocument({
- document_id: file.document_id,
- semantic_identifier: file.name,
- });
+ if (file.link_url) {
+ window.open(file.link_url, "_blank");
+ } else {
+ setPresentingDocument({
+ document_id: file.document_id,
+ semantic_identifier: file.name,
+ });
+ }
};
const handleFileSelect = (
diff --git a/web/src/app/chat/my-documents/components/SelectedItemsList.tsx b/web/src/app/chat/my-documents/components/SelectedItemsList.tsx
index f2da20971..9256cbc3b 100644
--- a/web/src/app/chat/my-documents/components/SelectedItemsList.tsx
+++ b/web/src/app/chat/my-documents/components/SelectedItemsList.tsx
@@ -11,7 +11,7 @@ import {
useDocumentsContext,
} from "../DocumentsContext";
import { useDocumentSelection } from "../../useDocumentSelection";
-import { getFileIconFromFileName } from "@/lib/assistantIconUtils";
+import { getFileIconFromFileNameAndLink } from "@/lib/assistantIconUtils";
import { MinimalOnyxDocument } from "@/lib/search/interfaces";
import { UploadingFile } from "./FilePicker";
import { CircularProgress } from "../[id]/components/upload/CircularProgress";
@@ -35,10 +35,14 @@ export const SelectedItemsList: React.FC = ({
}) => {
const hasItems = folders.length > 0 || files.length > 0;
const openFile = (file: FileResponse) => {
- setPresentingDocument({
- semantic_identifier: file.name,
- document_id: file.document_id,
- });
+ if (file.link_url) {
+ window.open(file.link_url, "_blank");
+ } else {
+ setPresentingDocument({
+ semantic_identifier: file.name,
+ document_id: file.document_id,
+ });
+ }
};
return (
@@ -116,13 +120,12 @@ export const SelectedItemsList: React.FC = ({
onClick={() => openFile(file)}
>
- {getFileIconFromFileName(file.name)}
+ {getFileIconFromFileNameAndLink(file.name, file.link_url)}
{truncateString(file.name, 34)}
-