Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -310,14 +310,7 @@ class GoogleDrive_DocumentLoaders implements INode {

if (selectedFiles) {
// Load selected files (selectedFiles can be a single ID or comma-separated IDs)
let ids: string[] = []
if (typeof selectedFiles === 'string' && selectedFiles.startsWith('[') && selectedFiles.endsWith(']')) {
ids = convertMultiOptionsToStringArray(selectedFiles)
} else if (typeof selectedFiles === 'string') {
ids = [selectedFiles]
} else if (Array.isArray(selectedFiles)) {
ids = selectedFiles
}
const ids = this.normalizeSelectedFileIds(selectedFiles)
for (const id of ids) {
const fileInfo = await this.getFileInfo(id, accessToken, includeSharedDrives)
if (fileInfo && this.shouldProcessFile(fileInfo, fileTypes)) {
Expand Down Expand Up @@ -400,6 +393,44 @@ class GoogleDrive_DocumentLoaders implements INode {
}
}

private normalizeSelectedFileIds(selectedFiles: unknown): string[] {
if (!selectedFiles) return []

let rawItems: unknown[] = []

if (typeof selectedFiles === 'string') {
const trimmed = selectedFiles.trim()
if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
try {
rawItems = JSON.parse(trimmed)
} catch (error) {
rawItems = []
}
} else if (trimmed.includes(',')) {
rawItems = trimmed.split(',').map((item) => item.trim())
} else {
rawItems = [trimmed]
}
} else if (Array.isArray(selectedFiles)) {
rawItems = selectedFiles
} else {
rawItems = [selectedFiles]
}

const normalized = rawItems
.map((item) => {
if (typeof item === 'string') return item
if (item && typeof item === 'object') {
const maybeItem = item as { fileId?: string; id?: string }
return maybeItem.fileId || maybeItem.id
}
return undefined
})
.filter((value): value is string => Boolean(value))

return Array.from(new Set(normalized))
}

private async getFileInfo(fileId: string, accessToken: string, includeSharedDrives: boolean): Promise<any> {
const url = new URL(`https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}`)
url.searchParams.append('fields', 'id, name, mimeType, size, createdTime, modifiedTime, parents, webViewLink, driveId')
Expand Down
58 changes: 49 additions & 9 deletions packages/ui/src/ui-component/drive/GoogleDrivePicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ const useGooglePicker = (accessToken, onFilesSelected) => {

export const GoogleDrivePicker = ({ onChange, value, disabled, credentialId, credentialData, handleCredentialDataChange }) => {
const dispatch = useDispatch()
const previousCredentialIdRef = useRef(null)
const [selectedFiles, setSelectedFiles] = useState(() => {
try {
return value ? JSON.parse(value) : []
Expand Down Expand Up @@ -213,22 +214,40 @@ export const GoogleDrivePicker = ({ onChange, value, disabled, credentialId, cre

const { createPicker, closePicker, pickerInstance } = useGooglePicker(accessToken, handleFilesSelected)

// Load credential data on mount and clear files when credential changes
// Load credential data on mount and clear files only when credential changes
useEffect(() => {
if (credentialId) {
getCredentialDataApi.request(credentialId)

// Clear selected files when credential changes
setSelectedFiles([])
onChange(JSON.stringify([]))
const previousCredentialId = previousCredentialIdRef.current
if (previousCredentialId && previousCredentialId !== credentialId) {
// Clear selected files when credential changes
setSelectedFiles([])
onChange(JSON.stringify([]))

// Reset token state
setAccessToken(null)
setIsTokenExpired(false)
setIsReauthRequired(false)
// Reset token state
setAccessToken(null)
setIsTokenExpired(false)
setIsReauthRequired(false)
}

previousCredentialIdRef.current = credentialId
}
}, [credentialId])

// Sync local selections when value prop changes
useEffect(() => {
if (value === undefined) return
try {
const parsedValue = typeof value === 'string' ? JSON.parse(value) : value
if (Array.isArray(parsedValue)) {
setSelectedFiles(parsedValue)
}
} catch (error) {
console.error('Error parsing selected files value:', error)
}
}, [value])

// Handle credential data from prop
useEffect(() => {
if (credentialData?.plainDataObj) {
Expand Down Expand Up @@ -311,7 +330,28 @@ export const GoogleDrivePicker = ({ onChange, value, disabled, credentialId, cre

try {
setIsRefreshing(true)
await oauth2Api.refresh(credentialId)
try {
const response = await oauth2Api.refresh(credentialId)
const oauth2Message = response?.data?.message || ''
const oauth2Failed = response?.data?.success === false
const isMissingOauthConfig = oauth2Message.includes('Missing required OAuth configuration')

if (oauth2Failed && isMissingOauthConfig) {
await credentialsApi.refreshAccessToken({ credentialId })
} else if (oauth2Failed) {
throw new Error(oauth2Message || 'Error refreshing access token')
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || ''
const isMissingOauthConfig = errorMessage.includes('Missing required OAuth configuration')

if (!isMissingOauthConfig) {
throw error
}

await credentialsApi.refreshAccessToken({ credentialId })
}

getCredentialDataApi.request(credentialId)
setIsTokenExpired(false)
setIsReauthRequired(false)
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/views/docstore/DocStoreInputHandler.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ const DocStoreInputHandler = ({ inputParam, data, disabled = false, onNodeDataCh
{inputParam && data.name === 'gmail' && inputParam.name === 'selectedLabels' && (
<GmailLabelPicker
disabled={disabled}
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)}
onChange={(newValue) => handleDataChange({ inputParam, newValue })}
value={data.inputs[inputParam.name] ?? '[]'}
credentialId={selectedCredential}
credentialData={selectedCredentialData}
Expand All @@ -186,7 +186,7 @@ const DocStoreInputHandler = ({ inputParam, data, disabled = false, onNodeDataCh
{inputParam && data.name === 'googleDrive' && inputParam.name === 'selectedFiles' && (
<GoogleDrivePicker
disabled={disabled}
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)}
onChange={(newValue) => handleDataChange({ inputParam, newValue })}
value={data.inputs[inputParam.name] ?? '[]'}
credentialId={selectedCredential}
credentialData={selectedCredentialData}
Expand Down