(feat:connector) refactor, updated routes FE

This commit is contained in:
ManishMadan2882
2025-08-29 01:06:40 +05:30
parent f39ac9945f
commit 018273c6b2
3 changed files with 150 additions and 152 deletions

View File

@@ -1,7 +1,7 @@
import datetime
import json
import os
from functools import wraps
from bson.objectid import ObjectId
from flask import (
Blueprint,
@@ -13,7 +13,7 @@ from flask import (
from flask_restx import fields, Namespace, Resource
from application.agents.tools.tool_manager import ToolManager
from application.api.user.tasks import (
ingest_connector_task,
@@ -21,16 +21,16 @@ from application.api.user.tasks import (
from application.core.mongo_db import MongoDB
from application.core.settings import settings
from application.api import api
from application.storage.storage_creator import StorageCreator
from application.tts.google_tts import GoogleTTS
from application.utils import (
check_required_fields
)
from application.utils import num_tokens_from_string
from application.vectorstore.vector_creator import VectorCreator
from application.parser.connectors.connector_creator import ConnectorCreator
storage = StorageCreator.get_storage()
mongo = MongoDB.get_client()
db = mongo[settings.MONGO_DB_NAME]
@@ -40,9 +40,6 @@ connector = Blueprint("connector", __name__)
connectors_ns = Namespace("connectors", description="Connector operations", path="/")
api.add_namespace(connectors_ns)
current_dir = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
@connectors_ns.route("/api/connectors/upload")
@@ -438,8 +435,7 @@ class ConnectorFiles(Resource):
'name': metadata.get('file_name', 'Unknown File'),
'type': metadata.get('mime_type', 'unknown'),
'size': metadata.get('size', 'Unknown'),
'modifiedTime': metadata.get('modified_time', 'Unknown'),
'iconUrl': get_file_icon(metadata.get('mime_type', ''))
'modifiedTime': metadata.get('modified_time', 'Unknown')
})
return make_response(jsonify({"success": True, "files": files, "total": len(files)}), 200)
@@ -511,25 +507,3 @@ class ConnectorDisconnect(Resource):
return make_response(jsonify({"success": False, "error": str(e)}), 500)
def get_file_icon(mime_type):
"""Return appropriate icon URL based on file MIME type"""
icon_map = {
'application/vnd.google-apps.document': '/icons/google-docs.png',
'application/vnd.google-apps.spreadsheet': '/icons/google-sheets.png',
'application/vnd.google-apps.presentation': '/icons/google-slides.png',
'application/pdf': '/icons/pdf.png',
'text/plain': '/icons/text.png',
'application/msword': '/icons/word.png',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '/icons/word.png',
'application/vnd.ms-excel': '/icons/excel.png',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '/icons/excel.png',
'application/vnd.ms-powerpoint': '/icons/powerpoint.png',
'application/vnd.openxmlformats-officedocument.presentationml.presentation': '/icons/powerpoint.png',
'image/jpeg': '/icons/image.png',
'image/png': '/icons/image.png',
'image/gif': '/icons/image.png',
'video/mp4': '/icons/video.png',
'application/zip': '/icons/archive.png',
'application/x-zip-compressed': '/icons/archive.png',
}
return icon_map.get(mime_type, '/icons/generic-file.png')

View File

@@ -0,0 +1,112 @@
import React, { useRef } from 'react';
import { useSelector } from 'react-redux';
import { selectToken } from '../preferences/preferenceSlice';
interface ConnectorAuthProps {
provider: string;
onSuccess: (data: { session_token: string; user_email: string }) => void;
onError: (error: string) => void;
label?: string;
}
const providerLabel = (provider: string) => {
const map: Record<string, string> = {
google_drive: 'Google Drive',
};
return map[provider] || provider.replace(/_/g, ' ');
};
const ConnectorAuth: React.FC<ConnectorAuthProps> = ({ provider, onSuccess, onError, label }) => {
const token = useSelector(selectToken);
const completedRef = useRef(false);
const intervalRef = useRef<number | null>(null);
const cleanup = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
window.removeEventListener('message', handleAuthMessage as any);
};
const handleAuthMessage = (event: MessageEvent) => {
const successGeneric = event.data?.type === 'connector_auth_success';
const successProvider = event.data?.type === `${provider}_auth_success` || event.data?.type === 'google_drive_auth_success';
const errorProvider = event.data?.type === `${provider}_auth_error` || event.data?.type === 'google_drive_auth_error';
if (successGeneric || successProvider) {
completedRef.current = true;
cleanup();
onSuccess({
session_token: event.data.session_token,
user_email: event.data.user_email || 'Connected User',
});
} else if (errorProvider) {
completedRef.current = true;
cleanup();
onError(event.data.error || 'Authentication failed');
}
};
const handleAuth = async () => {
try {
completedRef.current = false;
cleanup();
const apiHost = import.meta.env.VITE_API_HOST;
const authResponse = await fetch(`${apiHost}/api/connectors/auth?provider=${provider}`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!authResponse.ok) {
throw new Error(`Failed to get authorization URL: ${authResponse.status}`);
}
const authData = await authResponse.json();
if (!authData.success || !authData.authorization_url) {
throw new Error(authData.error || 'Failed to get authorization URL');
}
const authWindow = window.open(
authData.authorization_url,
`${provider}-auth`,
'width=500,height=600,scrollbars=yes,resizable=yes'
);
if (!authWindow) {
throw new Error('Failed to open authentication window. Please allow popups.');
}
window.addEventListener('message', handleAuthMessage as any);
const checkClosed = window.setInterval(() => {
if (authWindow.closed) {
clearInterval(checkClosed);
window.removeEventListener('message', handleAuthMessage as any);
if (!completedRef.current) {
onError('Authentication was cancelled');
}
}
}, 1000);
intervalRef.current = checkClosed;
} catch (error) {
onError(error instanceof Error ? error.message : 'Authentication failed');
}
};
const buttonLabel = label || `Connect ${providerLabel(provider)}`;
return (
<button
onClick={handleAuth}
className="w-full flex items-center justify-center gap-2 rounded-lg bg-blue-500 px-4 py-3 text-white hover:bg-blue-600 transition-colors"
>
<svg className="h-5 w-5" viewBox="0 0 24 24">
<path fill="currentColor" d="M6.28 3l5.72 10H24l-5.72-10H6.28zm11.44 0L12 13l5.72 10H24L18.28 3h-.56zM0 13l5.72 10h5.72L5.72 13H0z"/>
</svg>
{buttonLabel}
</button>
);
};
export default ConnectorAuth;

View File

@@ -27,6 +27,7 @@ import {
} from './types/ingestor';
import FileIcon from '../assets/file.svg';
import FolderIcon from '../assets/folder.svg';
import ConnectorAuth from '../components/ConnectorAuth';
function Upload({
receivedFile = [],
@@ -329,8 +330,7 @@ function Upload({
data?.find(
(d: Doc) => d.type?.toLowerCase() === 'local',
),
),
);
));
});
setProgress(
(progress) =>
@@ -514,13 +514,13 @@ function Upload({
try {
const apiHost = import.meta.env.VITE_API_HOST;
const validateResponse = await fetch(`${apiHost}/api/google-drive/validate-session`, {
const validateResponse = await fetch(`${apiHost}/api/connectors/validate-session`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ session_token: sessionToken })
body: JSON.stringify({ provider: 'google_drive', session_token: sessionToken })
});
if (!validateResponse.ok) {
@@ -547,94 +547,6 @@ function Upload({
}
};
const handleGoogleDriveConnect = async () => {
console.log('Google Drive connect button clicked');
setIsAuthenticating(true);
setAuthError('');
const existingToken = localStorage.getItem('google_drive_session_token');
if (existingToken) {
fetchUserEmailAndLoadFiles(existingToken);
setIsAuthenticating(false);
return;
}
try {
const apiHost = import.meta.env.VITE_API_HOST;
const authResponse = await fetch(`${apiHost}/api/google-drive/auth`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!authResponse.ok) {
throw new Error(`Failed to get authorization URL: ${authResponse.status}`);
}
const authData = await authResponse.json();
if (!authData.success || !authData.authorization_url) {
throw new Error(authData.error || 'Failed to get authorization URL');
}
console.log('Opening Google OAuth window...');
const authWindow = window.open(
authData.authorization_url,
'google-drive-auth',
'width=500,height=600,scrollbars=yes,resizable=yes'
);
if (!authWindow) {
throw new Error('Failed to open authentication window. Please allow popups.');
}
const handleAuthMessage = (event: MessageEvent) => {
console.log('Received message event:', event.data);
if (event.data.type === 'google_drive_auth_success') {
console.log('OAuth success received:', event.data);
setUserEmail(event.data.user_email || 'Connected User');
setIsGoogleDriveConnected(true);
setIsAuthenticating(false);
setAuthError('');
if (event.data.session_token) {
localStorage.setItem('google_drive_session_token', event.data.session_token);
}
window.removeEventListener('message', handleAuthMessage);
loadGoogleDriveFiles(event.data.session_token, null);
} else if (event.data.type === 'google_drive_auth_error') {
console.error('OAuth error received:', event.data);
setAuthError(event.data.error || 'Authentication failed. Please make sure to grant all requested permissions, including offline access. You may need to revoke previous access and re-authorize.');
setIsAuthenticating(false);
setIsGoogleDriveConnected(false);
window.removeEventListener('message', handleAuthMessage);
}
};
window.addEventListener('message', handleAuthMessage);
const checkClosed = setInterval(() => {
if (authWindow.closed) {
clearInterval(checkClosed);
window.removeEventListener('message', handleAuthMessage);
if (!isGoogleDriveConnected && !isAuthenticating) {
setAuthError('Authentication was cancelled');
}
}
}, 1000);
} catch (error) {
console.error('Error during Google Drive authentication:', error);
setAuthError(error instanceof Error ? error.message : 'Authentication failed');
setIsAuthenticating(false);
}
};
const loadGoogleDriveFiles = async (sessionToken: string, folderId?: string | null) => {
setIsLoadingFiles(true);
@@ -648,13 +560,13 @@ function Upload({
requestBody.folder_id = folderId;
}
const filesResponse = await fetch(`${apiHost}/api/google-drive/files`, {
const filesResponse = await fetch(`${apiHost}/api/connectors/files`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(requestBody)
body: JSON.stringify({ ...requestBody, provider: 'google_drive' })
});
if (!filesResponse.ok) {
@@ -919,7 +831,7 @@ function Upload({
{files.map((file) => (
<p
key={file.name}
className="text-gray-6000 truncate overflow-hidden text-ellipsis"
className="text-gray-6000 dark:text-[#ececf1] truncate overflow-hidden text-ellipsis"
title={file.name}
>
{file.name}
@@ -973,25 +885,25 @@ function Upload({
)}
{!isGoogleDriveConnected ? (
<button
onClick={handleGoogleDriveConnect}
disabled={isAuthenticating}
className="w-full flex items-center justify-center gap-2 rounded-lg bg-blue-500 px-4 py-3 text-white hover:bg-blue-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{isAuthenticating ? (
<>
<div className="h-5 w-5 animate-spin rounded-full border-2 border-white border-t-transparent"></div>
Connecting to Google...
</>
) : (
<>
<svg className="h-5 w-5" viewBox="0 0 24 24">
<path fill="currentColor" d="M6.28 3l5.72 10H24l-5.72-10H6.28zm11.44 0L12 13l5.72 10H24L18.28 3h-.56zM0 13l5.72 10h5.72L5.72 13H0z"/>
</svg>
Sign in with Google Drive
</>
)}
</button>
<ConnectorAuth
provider="google_drive"
onSuccess={(data) => {
setUserEmail(data.user_email);
setIsGoogleDriveConnected(true);
setIsAuthenticating(false);
setAuthError('');
if (data.session_token) {
localStorage.setItem('google_drive_session_token', data.session_token);
loadGoogleDriveFiles(data.session_token, null);
}
}}
onError={(error) => {
setAuthError(error);
setIsAuthenticating(false);
setIsGoogleDriveConnected(false);
}}
/>
) : (
<div className="space-y-4">
{/* Connection Status */}
@@ -1013,13 +925,13 @@ function Upload({
setAuthError('');
const apiHost = import.meta.env.VITE_API_HOST;
fetch(`${apiHost}/api/google-drive/disconnect`, {
fetch(`${apiHost}/api/connectors/disconnect`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ session_token: localStorage.getItem('google_drive_session_token') })
body: JSON.stringify({ provider: 'google_drive', session_token: localStorage.getItem('google_drive_session_token') })
}).catch(err => console.error('Error disconnecting from Google Drive:', err));
}}
className="text-white hover:text-gray-200 text-xs underline"
@@ -1111,7 +1023,7 @@ function Upload({
)}
<div className="flex-1 min-w-0">
<p
className={`text-sm font-medium truncate ${
className={`text-sm font-medium truncate dark:text-[#ececf1] ${
file.type === 'application/vnd.google-apps.folder' || file.isFolder
? 'cursor-pointer hover:text-blue-600'
: ''