/** * SharePoint node config — connection selector, paths, search. * All nodes use SharepointBrowseTree with the selected connection (fetchBrowse + onLoadChildren). * Folder-style nodes (list, upload target, copy destination): folders only, folder selection. * File-style nodes (read, download, find path, copy source): file selection; folders expand only. */ import React, { useEffect, useState, useCallback } from 'react'; import type { NodeConfigRendererProps } from './types'; import { fetchConnections, fetchBrowse, type UserConnection, type BrowseEntry } from '../../../../api/workflowApi'; import { SharepointBrowseTree } from '../../../FolderTree/SharepointBrowseTree'; import { useLanguage } from '../../../../providers/language/LanguageContext'; const browseDetailsStyle: React.CSSProperties = { marginTop: 12, border: '1px solid var(--border-color, #e0e0e0)', borderRadius: 6, background: 'var(--bg-secondary, #f8f9fa)', overflow: 'hidden', }; const browseSummaryStyle: React.CSSProperties = { padding: '0.5rem 0.75rem', cursor: 'pointer', fontWeight: 500, fontSize: '0.875rem', display: 'flex', alignItems: 'center', gap: '0.5rem', userSelect: 'none', }; const browseBodyStyle: React.CSSProperties = { padding: '0.5rem 0.75rem', borderTop: '1px solid var(--border-color, #e0e0e0)', maxHeight: 280, overflowY: 'auto', }; function browsePanelTitle(nodeType: string): string { switch (nodeType) { case 'sharepoint.uploadFile': return 'Zielordner durchsuchen'; case 'sharepoint.listFiles': return 'Ordner durchsuchen'; case 'sharepoint.readFile': return 'Datei auswählen'; case 'sharepoint.downloadFile': return 'Datei auswählen'; case 'sharepoint.findFile': return 'Pfad aus Bibliothek wählen'; default: return 'SharePoint durchsuchen'; } } /** Folder / location pickers — tree shows folders only; selecting sets folder path. */ function isFolderPickerNode(nodeType: string): boolean { return nodeType === 'sharepoint.uploadFile' || nodeType === 'sharepoint.listFiles'; } export const SharePointNodeConfig: React.FC = ({ params, updateParam, instanceId, request, nodeType = 'sharepoint.findFile', }) => { const { t } = useLanguage(); const [connections, setConnections] = useState([]); const [browseExpanded, setBrowseExpanded] = useState(false); const [findFileBrowseExpanded, setFindFileBrowseExpanded] = useState(false); const [copySourceExpanded, setCopySourceExpanded] = useState(false); const [copyDestExpanded, setCopyDestExpanded] = useState(false); const [connectionsLoading, setConnectionsLoading] = useState(false); const connectionId = (params.connectionId as string) ?? ''; const path = (params.path as string) ?? (params.filePath as string) ?? ''; useEffect(() => { if (instanceId && request) { setConnectionsLoading(true); fetchConnections(request, instanceId) .then(setConnections) .catch(() => setConnections([])) .finally(() => setConnectionsLoading(false)); } }, [instanceId, request]); const loadChildren = useCallback( async (pathToLoad: string): Promise => { if (!instanceId || !request || !connectionId) return []; const r = await fetchBrowse(request, instanceId, connectionId, 'sharepoint', pathToLoad); return r?.items ?? []; }, [instanceId, request, connectionId] ); const selectPath = useCallback( (p: string) => { updateParam('path', p); setBrowseExpanded(false); }, [updateParam] ); const selectSearchQueryFromFile = useCallback( (p: string) => { updateParam('searchQuery', p); setFindFileBrowseExpanded(false); }, [updateParam] ); const selectSourcePath = useCallback( (p: string) => { updateParam('sourcePath', p); setCopySourceExpanded(false); }, [updateParam] ); const selectDestPath = useCallback( (p: string) => { updateParam('destPath', p); setCopyDestExpanded(false); }, [updateParam] ); const needsSearch = nodeType === 'sharepoint.findFile'; const needsSiteId = false; const showPathFieldsForList = nodeType === 'sharepoint.listFiles'; const showPathFieldsForFileUploadDownload = nodeType === 'sharepoint.readFile' || nodeType === 'sharepoint.uploadFile' || nodeType === 'sharepoint.downloadFile'; /** Path + browse (same tree wiring) for these types — not copyFile (copy uses its own trees). */ const showStandardPathBrowse = connectionId && (showPathFieldsForList || showPathFieldsForFileUploadDownload); const showFindFileBrowse = connectionId && needsSearch; return ( <>
{needsSearch && (
updateParam('searchQuery', e.target.value)} placeholder="/sites/SiteName/Shared Documents or search term" />
)} {showPathFieldsForList && (
updateParam('path', e.target.value)} placeholder="/ or /sites/SiteName/Shared Documents/Folder" />
)} {showPathFieldsForFileUploadDownload && (
updateParam('path', e.target.value)} placeholder={ nodeType === 'sharepoint.downloadFile' ? '/sites/SiteName/Shared Documents/file.pdf' : nodeType === 'sharepoint.uploadFile' ? '/sites/.../Shared Documents/TargetFolder/' : 'File path' } />
)} {needsSiteId && (
updateParam('siteId', e.target.value)} placeholder={t('sharePointNodeConfig.sharepointSiteId')} />
)} {nodeType === 'sharepoint.copyFile' && ( <>
updateParam('sourcePath', e.target.value)} placeholder="/sites/.../folder/file.pdf" />
updateParam('destPath', e.target.value)} placeholder="/sites/.../target-folder/" />
{connectionId && ( <>
setCopySourceExpanded((e.target as HTMLDetailsElement).open)} style={browseDetailsStyle} > 📂 Quelldatei durchsuchen
setCopyDestExpanded((e.target as HTMLDetailsElement).open)} style={{ ...browseDetailsStyle, marginTop: 8 }} > 📂 Zielordner durchsuchen
{}} onSelectFolder={selectDestPath} selectedPath={(params.destPath as string) || null} />
)} )} {showStandardPathBrowse && (
setBrowseExpanded((e.target as HTMLDetailsElement).open)} style={browseDetailsStyle} > 📂 {browsePanelTitle(nodeType)}
{isFolderPickerNode(nodeType) && ( {}} onSelectFolder={selectPath} selectedPath={path || null} /> )} {(nodeType === 'sharepoint.readFile' || nodeType === 'sharepoint.downloadFile') && ( )}
)} {showFindFileBrowse && (
setFindFileBrowseExpanded((e.target as HTMLDetailsElement).open)} style={browseDetailsStyle} > 📂 {browsePanelTitle('sharepoint.findFile')}
)} ); };