mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-30 09:03:15 +00:00
(lint) fe
This commit is contained in:
@@ -2,8 +2,11 @@ import React, { useState, useEffect } from 'react';
|
||||
import useDrivePicker from 'react-google-drive-picker';
|
||||
|
||||
import ConnectorAuth from './ConnectorAuth';
|
||||
import { getSessionToken, setSessionToken, removeSessionToken } from '../utils/providerUtils';
|
||||
|
||||
import {
|
||||
getSessionToken,
|
||||
setSessionToken,
|
||||
removeSessionToken,
|
||||
} from '../utils/providerUtils';
|
||||
|
||||
interface PickerFile {
|
||||
id: string;
|
||||
@@ -31,9 +34,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
const [authError, setAuthError] = useState<string>('');
|
||||
const [accessToken, setAccessToken] = useState<string | null>(null);
|
||||
const [isValidating, setIsValidating] = useState(false);
|
||||
|
||||
|
||||
const [openPicker] = useDrivePicker();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const sessionToken = getSessionToken('google_drive');
|
||||
if (sessionToken) {
|
||||
@@ -46,14 +49,20 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
const validateSession = async (sessionToken: string) => {
|
||||
try {
|
||||
const apiHost = import.meta.env.VITE_API_HOST;
|
||||
const validateResponse = await fetch(`${apiHost}/api/connectors/validate-session`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
const validateResponse = await fetch(
|
||||
`${apiHost}/api/connectors/validate-session`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
provider: 'google_drive',
|
||||
session_token: sessionToken,
|
||||
}),
|
||||
},
|
||||
body: JSON.stringify({ provider: 'google_drive', session_token: sessionToken })
|
||||
});
|
||||
);
|
||||
|
||||
if (!validateResponse.ok) {
|
||||
setIsConnected(false);
|
||||
@@ -72,7 +81,10 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
return true;
|
||||
} else {
|
||||
setIsConnected(false);
|
||||
setAuthError(validateData.error || 'Session expired. Please reconnect your account.');
|
||||
setAuthError(
|
||||
validateData.error ||
|
||||
'Session expired. Please reconnect your account.',
|
||||
);
|
||||
setIsValidating(false);
|
||||
return false;
|
||||
}
|
||||
@@ -87,21 +99,23 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
|
||||
const handleOpenPicker = async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
|
||||
const sessionToken = getSessionToken('google_drive');
|
||||
|
||||
|
||||
if (!sessionToken) {
|
||||
setAuthError('No valid session found. Please reconnect to Google Drive.');
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!accessToken) {
|
||||
setAuthError('No access token available. Please reconnect to Google Drive.');
|
||||
setAuthError(
|
||||
'No access token available. Please reconnect to Google Drive.',
|
||||
);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const clientId: string = import.meta.env.VITE_GOOGLE_CLIENT_ID;
|
||||
|
||||
@@ -117,17 +131,18 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
|
||||
openPicker({
|
||||
clientId: clientId,
|
||||
developerKey: "",
|
||||
developerKey: '',
|
||||
appId: appId,
|
||||
setSelectFolderEnabled: false,
|
||||
viewId: "DOCS",
|
||||
viewId: 'DOCS',
|
||||
showUploadView: false,
|
||||
showUploadFolders: false,
|
||||
supportDrives: false,
|
||||
multiselect: true,
|
||||
token: accessToken,
|
||||
viewMimeTypes: 'application/vnd.google-apps.document,application/vnd.google-apps.presentation,application/vnd.google-apps.spreadsheet,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.ms-powerpoint,application/vnd.ms-excel,text/plain,text/csv,text/html,text/markdown,text/x-rst,application/json,application/epub+zip,application/rtf,image/jpeg,image/jpg,image/png',
|
||||
callbackFunction: (data:any) => {
|
||||
viewMimeTypes:
|
||||
'application/vnd.google-apps.document,application/vnd.google-apps.presentation,application/vnd.google-apps.spreadsheet,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.ms-powerpoint,application/vnd.ms-excel,text/plain,text/csv,text/html,text/markdown,text/x-rst,application/json,application/epub+zip,application/rtf,image/jpeg,image/jpg,image/png',
|
||||
callbackFunction: (data: any) => {
|
||||
setIsLoading(false);
|
||||
if (data.action === 'picked') {
|
||||
const docs = data.docs;
|
||||
@@ -136,14 +151,14 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
const newFolders: PickerFile[] = [];
|
||||
|
||||
docs.forEach((doc: any) => {
|
||||
const item = {
|
||||
id: doc.id,
|
||||
name: doc.name,
|
||||
mimeType: doc.mimeType,
|
||||
iconUrl: doc.iconUrl || '',
|
||||
description: doc.description,
|
||||
sizeBytes: doc.sizeBytes
|
||||
};
|
||||
const item = {
|
||||
id: doc.id,
|
||||
name: doc.name,
|
||||
mimeType: doc.mimeType,
|
||||
iconUrl: doc.iconUrl || '',
|
||||
description: doc.description,
|
||||
sizeBytes: doc.sizeBytes,
|
||||
};
|
||||
|
||||
if (doc.mimeType === 'application/vnd.google-apps.folder') {
|
||||
newFolders.push(item);
|
||||
@@ -152,20 +167,26 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
}
|
||||
});
|
||||
|
||||
setSelectedFiles(prevFiles => {
|
||||
const existingFileIds = new Set(prevFiles.map(file => file.id));
|
||||
const uniqueNewFiles = newFiles.filter(file => !existingFileIds.has(file.id));
|
||||
setSelectedFiles((prevFiles) => {
|
||||
const existingFileIds = new Set(prevFiles.map((file) => file.id));
|
||||
const uniqueNewFiles = newFiles.filter(
|
||||
(file) => !existingFileIds.has(file.id),
|
||||
);
|
||||
return [...prevFiles, ...uniqueNewFiles];
|
||||
});
|
||||
|
||||
setSelectedFolders(prevFolders => {
|
||||
const existingFolderIds = new Set(prevFolders.map(folder => folder.id));
|
||||
const uniqueNewFolders = newFolders.filter(folder => !existingFolderIds.has(folder.id));
|
||||
setSelectedFolders((prevFolders) => {
|
||||
const existingFolderIds = new Set(
|
||||
prevFolders.map((folder) => folder.id),
|
||||
);
|
||||
const uniqueNewFolders = newFolders.filter(
|
||||
(folder) => !existingFolderIds.has(folder.id),
|
||||
);
|
||||
return [...prevFolders, ...uniqueNewFolders];
|
||||
});
|
||||
onSelectionChange(
|
||||
[...selectedFiles, ...newFiles].map(file => file.id),
|
||||
[...selectedFolders, ...newFolders].map(folder => folder.id)
|
||||
[...selectedFiles, ...newFiles].map((file) => file.id),
|
||||
[...selectedFolders, ...newFolders].map((folder) => folder.id),
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -186,9 +207,12 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ provider: 'google_drive', session_token: sessionToken })
|
||||
body: JSON.stringify({
|
||||
provider: 'google_drive',
|
||||
session_token: sessionToken,
|
||||
}),
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Error disconnecting from Google Drive:', err);
|
||||
@@ -207,24 +231,24 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
|
||||
const ConnectedStateSkeleton = () => (
|
||||
<div className="mb-4">
|
||||
<div className="w-full flex items-center justify-between rounded-[10px] bg-gray-200 dark:bg-gray-700 px-4 py-2 animate-pulse">
|
||||
<div className="flex w-full animate-pulse items-center justify-between rounded-[10px] bg-gray-200 px-4 py-2 dark:bg-gray-700">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-4 w-4 bg-gray-300 dark:bg-gray-600 rounded"></div>
|
||||
<div className="h-4 w-32 bg-gray-300 dark:bg-gray-600 rounded"></div>
|
||||
<div className="h-4 w-4 rounded bg-gray-300 dark:bg-gray-600"></div>
|
||||
<div className="h-4 w-32 rounded bg-gray-300 dark:bg-gray-600"></div>
|
||||
</div>
|
||||
<div className="h-4 w-16 bg-gray-300 dark:bg-gray-600 rounded"></div>
|
||||
<div className="h-4 w-16 rounded bg-gray-300 dark:bg-gray-600"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const FilesSectionSkeleton = () => (
|
||||
<div className="border border-[#EEE6FF78] rounded-lg dark:border-[#6A6A6A]">
|
||||
<div className="rounded-lg border border-[#EEE6FF78] dark:border-[#6A6A6A]">
|
||||
<div className="p-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<div className="h-5 w-24 bg-gray-200 dark:bg-gray-700 rounded animate-pulse"></div>
|
||||
<div className="h-8 w-24 bg-gray-200 dark:bg-gray-700 rounded animate-pulse"></div>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div className="h-5 w-24 animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
|
||||
<div className="h-8 w-24 animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div className="h-4 w-40 bg-gray-200 dark:bg-gray-700 rounded animate-pulse"></div>
|
||||
<div className="h-4 w-40 animate-pulse rounded bg-gray-200 dark:bg-gray-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -262,13 +286,13 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
/>
|
||||
|
||||
{isConnected && (
|
||||
<div className="border border-[#EEE6FF78] rounded-lg dark:border-[#6A6A6A]">
|
||||
<div className="rounded-lg border border-[#EEE6FF78] dark:border-[#6A6A6A]">
|
||||
<div className="p-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h3 className="text-sm font-medium">Selected Files</h3>
|
||||
<button
|
||||
onClick={() => handleOpenPicker()}
|
||||
className="bg-[#A076F6] hover:bg-[#8A5FD4] text-white text-sm py-1 px-3 rounded-md"
|
||||
className="rounded-md bg-[#A076F6] px-3 py-1 text-sm text-white hover:bg-[#8A5FD4]"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Loading...' : 'Select Files'}
|
||||
@@ -276,26 +300,42 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
</div>
|
||||
|
||||
{selectedFiles.length === 0 && selectedFolders.length === 0 ? (
|
||||
<p className="text-gray-600 dark:text-gray-400 text-sm">No files or folders selected</p>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
No files or folders selected
|
||||
</p>
|
||||
) : (
|
||||
<div className="max-h-60 overflow-y-auto">
|
||||
{selectedFolders.length > 0 && (
|
||||
<div className="mb-2">
|
||||
<h4 className="text-xs font-medium text-gray-500 mb-1">Folders</h4>
|
||||
<h4 className="mb-1 text-xs font-medium text-gray-500">
|
||||
Folders
|
||||
</h4>
|
||||
{selectedFolders.map((folder) => (
|
||||
<div key={folder.id} className="flex items-center p-2 border-b border-gray-200 dark:border-gray-700">
|
||||
<img src={folder.iconUrl} alt="Folder" className="w-5 h-5 mr-2" />
|
||||
<span className="text-sm truncate flex-1">{folder.name}</span>
|
||||
<div
|
||||
key={folder.id}
|
||||
className="flex items-center border-b border-gray-200 p-2 dark:border-gray-700"
|
||||
>
|
||||
<img
|
||||
src={folder.iconUrl}
|
||||
alt="Folder"
|
||||
className="mr-2 h-5 w-5"
|
||||
/>
|
||||
<span className="flex-1 truncate text-sm">
|
||||
{folder.name}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
const newSelectedFolders = selectedFolders.filter(f => f.id !== folder.id);
|
||||
const newSelectedFolders =
|
||||
selectedFolders.filter(
|
||||
(f) => f.id !== folder.id,
|
||||
);
|
||||
setSelectedFolders(newSelectedFolders);
|
||||
onSelectionChange(
|
||||
selectedFiles.map(f => f.id),
|
||||
newSelectedFolders.map(f => f.id)
|
||||
selectedFiles.map((f) => f.id),
|
||||
newSelectedFolders.map((f) => f.id),
|
||||
);
|
||||
}}
|
||||
className="text-red-500 hover:text-red-700 text-sm ml-2"
|
||||
className="ml-2 text-sm text-red-500 hover:text-red-700"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
@@ -306,21 +346,34 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
|
||||
{selectedFiles.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-xs font-medium text-gray-500 mb-1">Files</h4>
|
||||
<h4 className="mb-1 text-xs font-medium text-gray-500">
|
||||
Files
|
||||
</h4>
|
||||
{selectedFiles.map((file) => (
|
||||
<div key={file.id} className="flex items-center p-2 border-b border-gray-200 dark:border-gray-700">
|
||||
<img src={file.iconUrl} alt="File" className="w-5 h-5 mr-2" />
|
||||
<span className="text-sm truncate flex-1">{file.name}</span>
|
||||
<div
|
||||
key={file.id}
|
||||
className="flex items-center border-b border-gray-200 p-2 dark:border-gray-700"
|
||||
>
|
||||
<img
|
||||
src={file.iconUrl}
|
||||
alt="File"
|
||||
className="mr-2 h-5 w-5"
|
||||
/>
|
||||
<span className="flex-1 truncate text-sm">
|
||||
{file.name}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
const newSelectedFiles = selectedFiles.filter(f => f.id !== file.id);
|
||||
const newSelectedFiles = selectedFiles.filter(
|
||||
(f) => f.id !== file.id,
|
||||
);
|
||||
setSelectedFiles(newSelectedFiles);
|
||||
onSelectionChange(
|
||||
newSelectedFiles.map(f => f.id),
|
||||
selectedFolders.map(f => f.id)
|
||||
newSelectedFiles.map((f) => f.id),
|
||||
selectedFolders.map((f) => f.id),
|
||||
);
|
||||
}}
|
||||
className="text-red-500 hover:text-red-700 text-sm ml-2"
|
||||
className="ml-2 text-sm text-red-500 hover:text-red-700"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user