mirror of
https://github.com/onyx-dot-app/onyx.git
synced 2026-02-18 16:25:45 +00:00
Compare commits
17 Commits
ll
...
fix_empty_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
411f912b9f | ||
|
|
7de576ce55 | ||
|
|
b48ebeacab | ||
|
|
d7a2329580 | ||
|
|
4db048797c | ||
|
|
70197e8329 | ||
|
|
ca0738ed65 | ||
|
|
6a0e8a1f8c | ||
|
|
f055cbcbad | ||
|
|
2f3020a4d3 | ||
|
|
4bae1318bb | ||
|
|
11c3f44c76 | ||
|
|
cb38ac8a97 | ||
|
|
b2120b9f39 | ||
|
|
ccd372cc4a | ||
|
|
ea30f1de1e | ||
|
|
a7130681d9 |
@@ -0,0 +1,117 @@
|
||||
"""duplicated no-harm user file migration
|
||||
|
||||
Revision ID: 6a804aeb4830
|
||||
Revises: 8e1ac4f39a9f
|
||||
Create Date: 2025-04-01 07:26:10.539362
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
import datetime
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "6a804aeb4830"
|
||||
down_revision = "8e1ac4f39a9f"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Check if user_file table already exists
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
|
||||
if not inspector.has_table("user_file"):
|
||||
# Create user_folder table without parent_id
|
||||
op.create_table(
|
||||
"user_folder",
|
||||
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
||||
sa.Column("user_id", sa.UUID(), sa.ForeignKey("user.id"), nullable=True),
|
||||
sa.Column("name", sa.String(length=255), nullable=True),
|
||||
sa.Column("description", sa.String(length=255), nullable=True),
|
||||
sa.Column("display_priority", sa.Integer(), nullable=True, default=0),
|
||||
sa.Column(
|
||||
"created_at", sa.DateTime(timezone=True), server_default=sa.func.now()
|
||||
),
|
||||
)
|
||||
|
||||
# Create user_file table with folder_id instead of parent_folder_id
|
||||
op.create_table(
|
||||
"user_file",
|
||||
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
||||
sa.Column("user_id", sa.UUID(), sa.ForeignKey("user.id"), nullable=True),
|
||||
sa.Column(
|
||||
"folder_id",
|
||||
sa.Integer(),
|
||||
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),
|
||||
sa.Column("document_id", sa.String(length=255), nullable=False),
|
||||
sa.Column("name", sa.String(length=255), nullable=False),
|
||||
sa.Column(
|
||||
"created_at",
|
||||
sa.DateTime(),
|
||||
default=datetime.datetime.utcnow,
|
||||
),
|
||||
sa.Column(
|
||||
"cc_pair_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("connector_credential_pair.id"),
|
||||
nullable=True,
|
||||
unique=True,
|
||||
),
|
||||
)
|
||||
|
||||
# Create persona__user_file table
|
||||
op.create_table(
|
||||
"persona__user_file",
|
||||
sa.Column(
|
||||
"persona_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("persona.id"),
|
||||
primary_key=True,
|
||||
),
|
||||
sa.Column(
|
||||
"user_file_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("user_file.id"),
|
||||
primary_key=True,
|
||||
),
|
||||
)
|
||||
|
||||
# Create persona__user_folder table
|
||||
op.create_table(
|
||||
"persona__user_folder",
|
||||
sa.Column(
|
||||
"persona_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("persona.id"),
|
||||
primary_key=True,
|
||||
),
|
||||
sa.Column(
|
||||
"user_folder_id",
|
||||
sa.Integer(),
|
||||
sa.ForeignKey("user_folder.id"),
|
||||
primary_key=True,
|
||||
),
|
||||
)
|
||||
|
||||
op.add_column(
|
||||
"connector_credential_pair",
|
||||
sa.Column("is_user_file", sa.Boolean(), nullable=True, default=False),
|
||||
)
|
||||
|
||||
# Update existing records to have is_user_file=False instead of NULL
|
||||
op.execute(
|
||||
"UPDATE connector_credential_pair SET is_user_file = FALSE WHERE is_user_file IS NULL"
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
pass
|
||||
@@ -5,9 +5,9 @@ Revises: 3781a5eb12cb
|
||||
Create Date: 2025-01-26 16:08:21.551022
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import datetime
|
||||
from alembic import op
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -36,9 +36,6 @@ from onyx.utils.logger import setup_logger
|
||||
logger = setup_logger()
|
||||
router = APIRouter(prefix="/auth/saml")
|
||||
|
||||
# Define non-authenticated user roles that should be re-created during SAML login
|
||||
NON_AUTHENTICATED_ROLES = {UserRole.SLACK_USER, UserRole.EXT_PERM_USER}
|
||||
|
||||
|
||||
async def upsert_saml_user(email: str) -> User:
|
||||
logger.debug(f"Attempting to upsert SAML user with email: {email}")
|
||||
@@ -54,7 +51,7 @@ async def upsert_saml_user(email: str) -> User:
|
||||
try:
|
||||
user = await user_manager.get_by_email(email)
|
||||
# If user has a non-authenticated role, treat as non-existent
|
||||
if user.role in NON_AUTHENTICATED_ROLES:
|
||||
if not user.role.is_web_login():
|
||||
raise exceptions.UserNotExists()
|
||||
return user
|
||||
except exceptions.UserNotExists:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
@@ -507,24 +506,11 @@ async def setup_tenant(tenant_id: str) -> None:
|
||||
try:
|
||||
token = CURRENT_TENANT_ID_CONTEXTVAR.set(tenant_id)
|
||||
|
||||
# Run Alembic migrations in a completely isolated way
|
||||
# This function runs in a separate thread with its own event loop context
|
||||
def isolated_migration_runner():
|
||||
# Reset contextvar to prevent it from being shared with the parent thread
|
||||
# This ensures no shared asyncio primitives between threads
|
||||
token = CURRENT_TENANT_ID_CONTEXTVAR.set(tenant_id)
|
||||
try:
|
||||
# Run migrations in this isolated thread
|
||||
run_alembic_migrations(tenant_id)
|
||||
finally:
|
||||
# Clean up the contextvar
|
||||
CURRENT_TENANT_ID_CONTEXTVAR.reset(token)
|
||||
|
||||
# Use a dedicated ThreadPoolExecutor for complete isolation
|
||||
# This prevents asyncio loop/lock sharing issues
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
||||
loop = asyncio.get_running_loop()
|
||||
await loop.run_in_executor(executor, isolated_migration_runner)
|
||||
# Run Alembic migrations in a way that isolates it from the current event loop
|
||||
# Create a new event loop for this synchronous operation
|
||||
loop = asyncio.get_event_loop()
|
||||
# Use run_in_executor which properly isolates the thread execution
|
||||
await loop.run_in_executor(None, lambda: run_alembic_migrations(tenant_id))
|
||||
|
||||
# Configure the tenant with default settings
|
||||
with get_session_with_tenant(tenant_id=tenant_id) as db_session:
|
||||
|
||||
@@ -42,6 +42,7 @@ from onyx.context.search.retrieval.search_runner import (
|
||||
from onyx.db.engine import get_all_tenant_ids
|
||||
from onyx.db.engine import get_session_with_current_tenant
|
||||
from onyx.db.engine import get_session_with_tenant
|
||||
from onyx.db.engine import SqlEngine
|
||||
from onyx.db.models import SlackBot
|
||||
from onyx.db.search_settings import get_current_search_settings
|
||||
from onyx.db.slack_bot import fetch_slack_bot
|
||||
@@ -972,6 +973,9 @@ def _get_socket_client(
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Initialize the SqlEngine
|
||||
SqlEngine.init_engine(pool_size=20, max_overflow=5)
|
||||
|
||||
# Initialize the tenant handler which will manage tenant connections
|
||||
logger.info("Starting SlackbotHandler")
|
||||
tenant_handler = SlackbotHandler()
|
||||
|
||||
@@ -2,6 +2,8 @@ import json
|
||||
import os
|
||||
import time
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -40,10 +42,13 @@ def highspot_connector() -> HighspotConnector:
|
||||
return connector
|
||||
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="Accessing postgres that isn't available in connector only tests",
|
||||
@patch(
|
||||
"onyx.file_processing.extract_file_text.get_unstructured_api_key",
|
||||
return_value=None,
|
||||
)
|
||||
def test_highspot_connector_basic(highspot_connector: HighspotConnector) -> None:
|
||||
def test_highspot_connector_basic(
|
||||
mock_get_api_key: MagicMock, highspot_connector: HighspotConnector
|
||||
) -> None:
|
||||
"""Test basic functionality of the Highspot connector."""
|
||||
all_docs: list[Document] = []
|
||||
test_data = load_test_data()
|
||||
@@ -76,10 +81,13 @@ def test_highspot_connector_basic(highspot_connector: HighspotConnector) -> None
|
||||
assert len(section.text) > 0
|
||||
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="Possibly accessing postgres that isn't available in connector only tests",
|
||||
@patch(
|
||||
"onyx.file_processing.extract_file_text.get_unstructured_api_key",
|
||||
return_value=None,
|
||||
)
|
||||
def test_highspot_connector_slim(highspot_connector: HighspotConnector) -> None:
|
||||
def test_highspot_connector_slim(
|
||||
mock_get_api_key: MagicMock, highspot_connector: HighspotConnector
|
||||
) -> None:
|
||||
"""Test slim document retrieval."""
|
||||
# Get all doc IDs from the full connector
|
||||
all_full_doc_ids = set()
|
||||
|
||||
@@ -42,7 +42,6 @@ ENV NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING}
|
||||
ARG NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA
|
||||
ENV NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA=${NEXT_PUBLIC_NEW_CHAT_DIRECTS_TO_SAME_PERSONA}
|
||||
|
||||
# allow user to specify custom feedback options
|
||||
ARG NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS
|
||||
ENV NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS=${NEXT_PUBLIC_POSITIVE_PREDEFINED_FEEDBACK_OPTIONS}
|
||||
|
||||
|
||||
12090
web/package-lock.json
generated
12090
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -93,11 +93,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@chromatic-com/playwright": "^0.10.2",
|
||||
"@playwright/test": "^1.39.0",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/chrome": "^0.0.287",
|
||||
"@types/jest": "^29.5.14",
|
||||
"chromatic": "^11.25.2",
|
||||
"eslint": "^8.48.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-next": "^14.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "2.8.8",
|
||||
|
||||
@@ -17,7 +17,7 @@ export default function PostHogPageView(): null {
|
||||
// Track pageviews
|
||||
if (pathname) {
|
||||
let url = window.origin + pathname;
|
||||
if (searchParams.toString()) {
|
||||
if (searchParams?.toString()) {
|
||||
url = url + `?${searchParams.toString()}`;
|
||||
}
|
||||
posthog.capture("$pageview", {
|
||||
|
||||
@@ -149,7 +149,7 @@ export function AssistantEditor({
|
||||
const { refreshAssistants, isImageGenerationAvailable } = useAssistants();
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const isAdminPage = searchParams.get("admin") === "true";
|
||||
const isAdminPage = searchParams?.get("admin") === "true";
|
||||
|
||||
const { popup, setPopup } = usePopup();
|
||||
const { labels, refreshLabels, createLabel, updateLabel, deleteLabel } =
|
||||
@@ -469,8 +469,14 @@ export function AssistantEditor({
|
||||
description: Yup.string().required(
|
||||
"Must provide a description for the Assistant"
|
||||
),
|
||||
system_prompt: Yup.string(),
|
||||
task_prompt: Yup.string(),
|
||||
system_prompt: Yup.string().max(
|
||||
8000,
|
||||
"Instructions must be less than 8000 characters"
|
||||
),
|
||||
task_prompt: Yup.string().max(
|
||||
8000,
|
||||
"Reminders must be less than 8000 characters"
|
||||
),
|
||||
is_public: Yup.boolean().required(),
|
||||
document_set_ids: Yup.array().of(Yup.number()),
|
||||
num_chunks: Yup.number().nullable(),
|
||||
|
||||
@@ -302,11 +302,17 @@ export default function AddConnector({
|
||||
...connector_specific_config
|
||||
} = values;
|
||||
|
||||
// Apply transforms from connectors.ts configuration
|
||||
// Apply special transforms according to application logic
|
||||
const transformedConnectorSpecificConfig = Object.entries(
|
||||
connector_specific_config
|
||||
).reduce(
|
||||
(acc, [key, value]) => {
|
||||
// Filter out empty strings from arrays
|
||||
if (Array.isArray(value)) {
|
||||
value = (value as any[]).filter(
|
||||
(item) => typeof item !== "string" || item.trim() !== ""
|
||||
);
|
||||
}
|
||||
const matchingConfigValue = configuration.values.find(
|
||||
(configValue) => configValue.name === key
|
||||
);
|
||||
|
||||
@@ -26,8 +26,8 @@ export default function OAuthCallbackPage() {
|
||||
);
|
||||
|
||||
// Extract query parameters
|
||||
const code = searchParams.get("code");
|
||||
const state = searchParams.get("state");
|
||||
const code = searchParams?.get("code");
|
||||
const state = searchParams?.get("state");
|
||||
|
||||
const pathname = usePathname();
|
||||
const connector = pathname?.split("/")[3];
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useEffect, useState } from "react";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { AdminPageTitle } from "@/components/admin/Title";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Title from "@/components/ui/title";
|
||||
import { KeyIcon } from "@/components/icons/icons";
|
||||
import { getSourceMetadata, isValidSource } from "@/lib/sources";
|
||||
import { ConfluenceAccessibleResource, ValidSources } from "@/lib/types";
|
||||
@@ -74,7 +73,7 @@ export default function OAuthFinalizePage() {
|
||||
>([]);
|
||||
|
||||
// Extract query parameters
|
||||
const credentialParam = searchParams.get("credential");
|
||||
const credentialParam = searchParams?.get("credential");
|
||||
const credential = credentialParam ? parseInt(credentialParam, 10) : NaN;
|
||||
const pathname = usePathname();
|
||||
const connector = pathname?.split("/")[3];
|
||||
@@ -85,7 +84,7 @@ export default function OAuthFinalizePage() {
|
||||
// connector (url segment)= "google-drive"
|
||||
// sourceType (for looking up metadata) = "google_drive"
|
||||
|
||||
if (isNaN(credential)) {
|
||||
if (isNaN(credential) || !connector) {
|
||||
setStatusMessage("Improperly formed OAuth finalization request.");
|
||||
setStatusDetails("Invalid or missing credential id.");
|
||||
setIsError(true);
|
||||
|
||||
@@ -23,8 +23,8 @@ const ResetPasswordPage: React.FC = () => {
|
||||
const { popup, setPopup } = usePopup();
|
||||
const [isWorking, setIsWorking] = useState(false);
|
||||
const searchParams = useSearchParams();
|
||||
const token = searchParams.get("token");
|
||||
const tenantId = searchParams.get(TENANT_ID_COOKIE_NAME);
|
||||
const token = searchParams?.get("token");
|
||||
const tenantId = searchParams?.get(TENANT_ID_COOKIE_NAME);
|
||||
// Keep search param same name as cookie for simplicity
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -15,9 +15,9 @@ export function Verify({ user }: { user: User | null }) {
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const verify = useCallback(async () => {
|
||||
const token = searchParams.get("token");
|
||||
const token = searchParams?.get("token");
|
||||
const firstUser =
|
||||
searchParams.get("first_user") && NEXT_PUBLIC_CLOUD_ENABLED;
|
||||
searchParams?.get("first_user") && NEXT_PUBLIC_CLOUD_ENABLED;
|
||||
if (!token) {
|
||||
setError(
|
||||
"Missing verification token. Try requesting a new verification email."
|
||||
|
||||
@@ -196,7 +196,9 @@ export function ChatPage({
|
||||
setCurrentMessageFiles,
|
||||
} = useDocumentsContext();
|
||||
|
||||
const defaultAssistantIdRaw = searchParams.get(SEARCH_PARAM_NAMES.PERSONA_ID);
|
||||
const defaultAssistantIdRaw = searchParams?.get(
|
||||
SEARCH_PARAM_NAMES.PERSONA_ID
|
||||
);
|
||||
const defaultAssistantId = defaultAssistantIdRaw
|
||||
? parseInt(defaultAssistantIdRaw)
|
||||
: undefined;
|
||||
@@ -252,8 +254,8 @@ export function ChatPage({
|
||||
);
|
||||
|
||||
const { user, isAdmin } = useUser();
|
||||
const slackChatId = searchParams.get("slackChatId");
|
||||
const existingChatIdRaw = searchParams.get("chatId");
|
||||
const slackChatId = searchParams?.get("slackChatId");
|
||||
const existingChatIdRaw = searchParams?.get("chatId");
|
||||
|
||||
const [showHistorySidebar, setShowHistorySidebar] = useState(false);
|
||||
|
||||
@@ -275,7 +277,7 @@ export function ChatPage({
|
||||
|
||||
const processSearchParamsAndSubmitMessage = (searchParamsString: string) => {
|
||||
const newSearchParams = new URLSearchParams(searchParamsString);
|
||||
const message = newSearchParams.get("user-prompt");
|
||||
const message = newSearchParams?.get("user-prompt");
|
||||
|
||||
filterManager.buildFiltersFromQueryString(
|
||||
newSearchParams.toString(),
|
||||
@@ -284,7 +286,7 @@ export function ChatPage({
|
||||
tags
|
||||
);
|
||||
|
||||
const fileDescriptorString = newSearchParams.get(SEARCH_PARAM_NAMES.FILES);
|
||||
const fileDescriptorString = newSearchParams?.get(SEARCH_PARAM_NAMES.FILES);
|
||||
const overrideFileDescriptors: FileDescriptor[] = fileDescriptorString
|
||||
? JSON.parse(decodeURIComponent(fileDescriptorString))
|
||||
: [];
|
||||
@@ -324,7 +326,7 @@ export function ChatPage({
|
||||
: undefined
|
||||
);
|
||||
// Gather default temperature settings
|
||||
const search_param_temperature = searchParams.get(
|
||||
const search_param_temperature = searchParams?.get(
|
||||
SEARCH_PARAM_NAMES.TEMPERATURE
|
||||
);
|
||||
|
||||
@@ -551,7 +553,7 @@ export function ChatPage({
|
||||
if (
|
||||
newMessageHistory.length === 1 &&
|
||||
!submitOnLoadPerformed.current &&
|
||||
searchParams.get(SEARCH_PARAM_NAMES.SEEDED) === "true"
|
||||
searchParams?.get(SEARCH_PARAM_NAMES.SEEDED) === "true"
|
||||
) {
|
||||
submitOnLoadPerformed.current = true;
|
||||
const seededMessage = newMessageHistory[0].message;
|
||||
@@ -572,11 +574,11 @@ export function ChatPage({
|
||||
|
||||
initialSessionFetch();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [existingChatSessionId, searchParams.get(SEARCH_PARAM_NAMES.PERSONA_ID)]);
|
||||
}, [existingChatSessionId, searchParams?.get(SEARCH_PARAM_NAMES.PERSONA_ID)]);
|
||||
|
||||
useEffect(() => {
|
||||
const userFolderId = searchParams.get(SEARCH_PARAM_NAMES.USER_FOLDER_ID);
|
||||
const allMyDocuments = searchParams.get(
|
||||
const userFolderId = searchParams?.get(SEARCH_PARAM_NAMES.USER_FOLDER_ID);
|
||||
const allMyDocuments = searchParams?.get(
|
||||
SEARCH_PARAM_NAMES.ALL_MY_DOCUMENTS
|
||||
);
|
||||
|
||||
@@ -599,14 +601,14 @@ export function ChatPage({
|
||||
}
|
||||
}, [
|
||||
userFolders,
|
||||
searchParams.get(SEARCH_PARAM_NAMES.USER_FOLDER_ID),
|
||||
searchParams.get(SEARCH_PARAM_NAMES.ALL_MY_DOCUMENTS),
|
||||
searchParams?.get(SEARCH_PARAM_NAMES.USER_FOLDER_ID),
|
||||
searchParams?.get(SEARCH_PARAM_NAMES.ALL_MY_DOCUMENTS),
|
||||
addSelectedFolder,
|
||||
clearSelectedItems,
|
||||
]);
|
||||
|
||||
const [message, setMessage] = useState(
|
||||
searchParams.get(SEARCH_PARAM_NAMES.USER_PROMPT) || ""
|
||||
searchParams?.get(SEARCH_PARAM_NAMES.USER_PROMPT) || ""
|
||||
);
|
||||
|
||||
const [completeMessageDetail, setCompleteMessageDetail] = useState<
|
||||
@@ -1048,7 +1050,7 @@ export function ChatPage({
|
||||
|
||||
// Equivalent to `loadNewPageLogic`
|
||||
useEffect(() => {
|
||||
if (searchParams.get(SEARCH_PARAM_NAMES.SEND_ON_LOAD)) {
|
||||
if (searchParams?.get(SEARCH_PARAM_NAMES.SEND_ON_LOAD)) {
|
||||
processSearchParamsAndSubmitMessage(searchParams.toString());
|
||||
}
|
||||
}, [searchParams, router]);
|
||||
@@ -1231,7 +1233,7 @@ export function ChatPage({
|
||||
const isNewSession = chatSessionIdRef.current === null;
|
||||
|
||||
const searchParamBasedChatSessionName =
|
||||
searchParams.get(SEARCH_PARAM_NAMES.TITLE) || null;
|
||||
searchParams?.get(SEARCH_PARAM_NAMES.TITLE) || null;
|
||||
|
||||
if (isNewSession) {
|
||||
currChatSessionId = await createChatSession(
|
||||
@@ -1409,11 +1411,11 @@ export function ChatPage({
|
||||
modelVersion:
|
||||
modelOverride?.modelName ||
|
||||
llmManager.currentLlm.modelName ||
|
||||
searchParams.get(SEARCH_PARAM_NAMES.MODEL_VERSION) ||
|
||||
searchParams?.get(SEARCH_PARAM_NAMES.MODEL_VERSION) ||
|
||||
undefined,
|
||||
temperature: llmManager.temperature || undefined,
|
||||
systemPromptOverride:
|
||||
searchParams.get(SEARCH_PARAM_NAMES.SYSTEM_PROMPT) || undefined,
|
||||
searchParams?.get(SEARCH_PARAM_NAMES.SYSTEM_PROMPT) || undefined,
|
||||
useExistingUserMessage: isSeededChat,
|
||||
useLanggraph:
|
||||
settings?.settings.pro_search_enabled &&
|
||||
|
||||
@@ -668,7 +668,7 @@ const PARAMS_TO_SKIP = [
|
||||
];
|
||||
|
||||
export function buildChatUrl(
|
||||
existingSearchParams: ReadonlyURLSearchParams,
|
||||
existingSearchParams: ReadonlyURLSearchParams | null,
|
||||
chatSessionId: string | null,
|
||||
personaId: number | null,
|
||||
search?: boolean
|
||||
@@ -685,7 +685,7 @@ export function buildChatUrl(
|
||||
finalSearchParams.push(`${SEARCH_PARAM_NAMES.PERSONA_ID}=${personaId}`);
|
||||
}
|
||||
|
||||
existingSearchParams.forEach((value, key) => {
|
||||
existingSearchParams?.forEach((value, key) => {
|
||||
if (!PARAMS_TO_SKIP.includes(key)) {
|
||||
finalSearchParams.push(`${key}=${value}`);
|
||||
}
|
||||
@@ -719,7 +719,7 @@ export async function uploadFilesForChat(
|
||||
return [responseJson.files as FileDescriptor[], null];
|
||||
}
|
||||
|
||||
export async function useScrollonStream({
|
||||
export function useScrollonStream({
|
||||
chatState,
|
||||
scrollableDivRef,
|
||||
scrollDist,
|
||||
@@ -817,5 +817,5 @@ export async function useScrollonStream({
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [chatState, distance, scrollDist, scrollableDivRef]);
|
||||
}, [chatState, distance, scrollDist, scrollableDivRef, enableAutoScroll]);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ export const SEARCH_PARAM_NAMES = {
|
||||
SEND_ON_LOAD: "send-on-load",
|
||||
};
|
||||
|
||||
export function shouldSubmitOnLoad(searchParams: ReadonlyURLSearchParams) {
|
||||
const rawSubmitOnLoad = searchParams.get(SEARCH_PARAM_NAMES.SUBMIT_ON_LOAD);
|
||||
export function shouldSubmitOnLoad(
|
||||
searchParams: ReadonlyURLSearchParams | null
|
||||
) {
|
||||
const rawSubmitOnLoad = searchParams?.get(SEARCH_PARAM_NAMES.SUBMIT_ON_LOAD);
|
||||
if (rawSubmitOnLoad === "true" || rawSubmitOnLoad === "1") {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export function UserDropdown({
|
||||
|
||||
// Construct the current URL
|
||||
const currentUrl = `${pathname}${
|
||||
searchParams.toString() ? `?${searchParams.toString()}` : ""
|
||||
searchParams?.toString() ? `?${searchParams.toString()}` : ""
|
||||
}`;
|
||||
|
||||
// Encode the current URL to use as a redirect parameter
|
||||
|
||||
@@ -59,8 +59,8 @@ export function ClientLayout({
|
||||
const { llmProviders } = useChatContext();
|
||||
const { popup, setPopup } = usePopup();
|
||||
if (
|
||||
pathname.startsWith("/admin/connectors") ||
|
||||
pathname.startsWith("/admin/embeddings")
|
||||
(pathname && pathname.startsWith("/admin/connectors")) ||
|
||||
(pathname && pathname.startsWith("/admin/embeddings"))
|
||||
) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export const ChatProvider: React.FC<{
|
||||
const { sessions } = await response.json();
|
||||
setChatSessions(sessions);
|
||||
|
||||
const currentSessionId = searchParams.get("chatId");
|
||||
const currentSessionId = searchParams?.get("chatId");
|
||||
if (
|
||||
currentSessionId &&
|
||||
!sessions.some(
|
||||
|
||||
@@ -34,7 +34,7 @@ export const EmbeddingFormProvider: React.FC<{
|
||||
const pathname = usePathname();
|
||||
|
||||
// Initialize formStep based on the URL parameter
|
||||
const initialStep = parseInt(searchParams.get("step") || "0", 10);
|
||||
const initialStep = parseInt(searchParams?.get("step") || "0", 10);
|
||||
const [formStep, setFormStep] = useState(initialStep);
|
||||
const [formValues, setFormValues] = useState<Record<string, any>>({});
|
||||
|
||||
@@ -56,8 +56,10 @@ export const EmbeddingFormProvider: React.FC<{
|
||||
|
||||
useEffect(() => {
|
||||
// Update URL when formStep changes
|
||||
const updatedSearchParams = new URLSearchParams(searchParams.toString());
|
||||
const existingStep = updatedSearchParams.get("step");
|
||||
const updatedSearchParams = new URLSearchParams(
|
||||
searchParams?.toString() || ""
|
||||
);
|
||||
const existingStep = updatedSearchParams?.get("step");
|
||||
updatedSearchParams.set("step", formStep.toString());
|
||||
const newUrl = `${pathname}?${updatedSearchParams.toString()}`;
|
||||
|
||||
@@ -70,7 +72,7 @@ export const EmbeddingFormProvider: React.FC<{
|
||||
|
||||
// Update formStep when URL changes
|
||||
useEffect(() => {
|
||||
const stepFromUrl = parseInt(searchParams.get("step") || "0", 10);
|
||||
const stepFromUrl = parseInt(searchParams?.get("step") || "0", 10);
|
||||
if (stepFromUrl !== formStep) {
|
||||
setFormStep(stepFromUrl);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export const FormProvider: React.FC<{
|
||||
const pathname = usePathname();
|
||||
|
||||
// Initialize formStep based on the URL parameter
|
||||
const initialStep = parseInt(searchParams.get("step") || "0", 10);
|
||||
const initialStep = parseInt(searchParams?.get("step") || "0", 10);
|
||||
const [formStep, setFormStep] = useState(initialStep);
|
||||
const [formValues, setFormValues] = useState<Record<string, any>>({});
|
||||
|
||||
@@ -56,8 +56,10 @@ export const FormProvider: React.FC<{
|
||||
|
||||
useEffect(() => {
|
||||
// Update URL when formStep changes
|
||||
const updatedSearchParams = new URLSearchParams(searchParams.toString());
|
||||
const existingStep = updatedSearchParams.get("step");
|
||||
const updatedSearchParams = new URLSearchParams(
|
||||
searchParams?.toString() || ""
|
||||
);
|
||||
const existingStep = updatedSearchParams?.get("step");
|
||||
updatedSearchParams.set("step", formStep.toString());
|
||||
const newUrl = `${pathname}?${updatedSearchParams.toString()}`;
|
||||
|
||||
@@ -69,7 +71,7 @@ export const FormProvider: React.FC<{
|
||||
}, [formStep, router, pathname, searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
const stepFromUrl = parseInt(searchParams.get("step") || "0", 10);
|
||||
const stepFromUrl = parseInt(searchParams?.get("step") || "0", 10);
|
||||
if (stepFromUrl !== formStep) {
|
||||
setFormStep(stepFromUrl);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export const HealthCheckBanner = () => {
|
||||
useEffect(() => {
|
||||
if (userError && userError.status === 403) {
|
||||
logout().then(() => {
|
||||
if (!pathname.includes("/auth")) {
|
||||
if (!pathname?.includes("/auth")) {
|
||||
setShowLoggedOutModal(true);
|
||||
}
|
||||
});
|
||||
@@ -61,7 +61,7 @@ export const HealthCheckBanner = () => {
|
||||
expirationTimeoutRef.current = setTimeout(() => {
|
||||
setExpired(true);
|
||||
|
||||
if (!pathname.includes("/auth")) {
|
||||
if (!pathname?.includes("/auth")) {
|
||||
setShowLoggedOutModal(true);
|
||||
}
|
||||
}, timeUntilExpire);
|
||||
@@ -205,7 +205,7 @@ export const HealthCheckBanner = () => {
|
||||
}
|
||||
|
||||
if (error instanceof RedirectError || expired) {
|
||||
if (!pathname.includes("/auth")) {
|
||||
if (!pathname?.includes("/auth")) {
|
||||
setShowLoggedOutModal(true);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -19,12 +19,12 @@ function setWelcomeFlowComplete() {
|
||||
Cookies.set(COMPLETED_WELCOME_FLOW_COOKIE, "true", { expires: 365 });
|
||||
}
|
||||
|
||||
export function _CompletedWelcomeFlowDummyComponent() {
|
||||
export function CompletedWelcomeFlowDummyComponent() {
|
||||
setWelcomeFlowComplete();
|
||||
return null;
|
||||
}
|
||||
|
||||
export function _WelcomeModal({ user }: { user: User | null }) {
|
||||
export function WelcomeModal({ user }: { user: User | null }) {
|
||||
const router = useRouter();
|
||||
|
||||
const [providerOptions, setProviderOptions] = useState<
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
_CompletedWelcomeFlowDummyComponent,
|
||||
_WelcomeModal,
|
||||
CompletedWelcomeFlowDummyComponent,
|
||||
WelcomeModal as WelcomeModalComponent,
|
||||
} from "./WelcomeModal";
|
||||
import { COMPLETED_WELCOME_FLOW_COOKIE } from "./constants";
|
||||
import { User } from "@/lib/types";
|
||||
@@ -24,8 +24,8 @@ export function WelcomeModal({
|
||||
}) {
|
||||
const hasCompletedWelcomeFlow = hasCompletedWelcomeFlowSS(requestCookies);
|
||||
if (hasCompletedWelcomeFlow) {
|
||||
return <_CompletedWelcomeFlowDummyComponent />;
|
||||
return <CompletedWelcomeFlowDummyComponent />;
|
||||
}
|
||||
|
||||
return <_WelcomeModal user={user} />;
|
||||
return <WelcomeModalComponent user={user} />;
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ export function NewTeamModal() {
|
||||
const { setPopup } = usePopup();
|
||||
|
||||
useEffect(() => {
|
||||
const hasNewTeamParam = searchParams.has("new_team");
|
||||
const hasNewTeamParam = searchParams?.has("new_team");
|
||||
if (hasNewTeamParam) {
|
||||
setShowNewTeamModal(true);
|
||||
fetchTenantInfo();
|
||||
|
||||
// Remove the new_team parameter from the URL without page reload
|
||||
const newParams = new URLSearchParams(searchParams.toString());
|
||||
const newParams = new URLSearchParams(searchParams?.toString() || "");
|
||||
newParams.delete("new_team");
|
||||
const newUrl =
|
||||
window.location.pathname +
|
||||
|
||||
@@ -16,7 +16,7 @@ export const usePopupFromQuery = (messages: PopupMessages) => {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// Get the value for search param with key "message"
|
||||
const messageValue = searchParams.get("message");
|
||||
const messageValue = searchParams?.get("message");
|
||||
|
||||
// Check if any key from messages object is present in search params
|
||||
if (messageValue && messageValue in messages) {
|
||||
|
||||
@@ -148,7 +148,7 @@ function usePaginatedFetch<T extends PaginatedType>({
|
||||
// Updates the URL with the current page number
|
||||
const updatePageUrl = useCallback(
|
||||
(page: number) => {
|
||||
if (currentPath) {
|
||||
if (currentPath && searchParams) {
|
||||
const params = new URLSearchParams(searchParams);
|
||||
params.set("page", page.toString());
|
||||
router.replace(`${currentPath}?${params.toString()}`, {
|
||||
|
||||
@@ -1333,10 +1333,10 @@ export function createConnectorValidationSchema(
|
||||
): Yup.ObjectSchema<Record<string, any>> {
|
||||
const configuration = connectorConfigs[connector];
|
||||
|
||||
return Yup.object().shape({
|
||||
const object = Yup.object().shape({
|
||||
access_type: Yup.string().required("Access Type is required"),
|
||||
name: Yup.string().required("Connector Name is required"),
|
||||
...configuration.values.reduce(
|
||||
...[...configuration.values, ...configuration.advanced_values].reduce(
|
||||
(acc, field) => {
|
||||
let schema: any =
|
||||
field.type === "select"
|
||||
@@ -1363,6 +1363,8 @@ export function createConnectorValidationSchema(
|
||||
pruneFreq: Yup.number().min(0, "Prune frequency must be non-negative"),
|
||||
refreshFreq: Yup.number().min(0, "Refresh frequency must be non-negative"),
|
||||
});
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
export const defaultPruneFreqDays = 30; // 30 days
|
||||
|
||||
Reference in New Issue
Block a user