245 lines
8.8 KiB
TypeScript
245 lines
8.8 KiB
TypeScript
/**
|
|
* SharePoint node config - connection selector, path, search query.
|
|
* Uses SharepointBrowseTree (FolderTree-style) for file selection.
|
|
*/
|
|
|
|
import React, { useEffect, useState, useCallback } from 'react';
|
|
import type { NodeConfigRendererProps } from './types';
|
|
import { fetchConnections, fetchBrowse, type UserConnection, type BrowseEntry } from '../../../api/automation2Api';
|
|
import { SharepointBrowseTree } from '../../FolderTree/SharepointBrowseTree';
|
|
|
|
export const SharePointNodeConfig: React.FC<NodeConfigRendererProps> = ({
|
|
params,
|
|
updateParam,
|
|
instanceId,
|
|
request,
|
|
nodeType = 'sharepoint.findFile',
|
|
}) => {
|
|
const [connections, setConnections] = useState<UserConnection[]>([]);
|
|
const [browseExpanded, setBrowseExpanded] = useState(false);
|
|
const [copySourceExpanded, setCopySourceExpanded] = useState(false);
|
|
const [copyDestExpanded, setCopyDestExpanded] = useState(false);
|
|
const [connectionsLoading, setConnectionsLoading] = useState(false);
|
|
|
|
const connectionId = (params.connectionId as string) ?? '';
|
|
const pathParam = 'path';
|
|
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<BrowseEntry[]> => {
|
|
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(pathParam, p);
|
|
setBrowseExpanded(false);
|
|
},
|
|
[updateParam, pathParam]
|
|
);
|
|
|
|
const selectSourcePath = useCallback(
|
|
(p: string) => {
|
|
updateParam('sourcePath', p);
|
|
setCopySourceExpanded(false);
|
|
},
|
|
[updateParam]
|
|
);
|
|
|
|
const selectDestPath = useCallback(
|
|
(p: string) => {
|
|
updateParam('destPath', p);
|
|
setCopyDestExpanded(false);
|
|
},
|
|
[updateParam]
|
|
);
|
|
|
|
const needsPath = !['sharepoint.findFile'].includes(nodeType);
|
|
const needsSearch = nodeType === 'sharepoint.findFile';
|
|
const needsSiteId = false;
|
|
const hasPathInput = ['sharepoint.readFile', 'sharepoint.uploadFile', 'sharepoint.downloadFile', 'sharepoint.copyFile'].includes(nodeType);
|
|
|
|
return (
|
|
<>
|
|
<div>
|
|
<label>Connection</label>
|
|
<select
|
|
value={connectionId}
|
|
onChange={(e) => updateParam('connectionId', e.target.value)}
|
|
disabled={connectionsLoading}
|
|
>
|
|
<option value="">{connectionsLoading ? 'Loading...' : 'Select connection'}</option>
|
|
{connections.map((c) => (
|
|
<option key={c.id} value={c.id}>
|
|
{c.externalUsername ?? c.id}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
{needsSearch && (
|
|
<div>
|
|
<label>Search query / path</label>
|
|
<input
|
|
value={(params.searchQuery as string) ?? ''}
|
|
onChange={(e) => updateParam('searchQuery', e.target.value)}
|
|
placeholder="/sites/SiteName/Shared Documents or search term"
|
|
/>
|
|
</div>
|
|
)}
|
|
{needsPath && nodeType === 'sharepoint.listFiles' && (
|
|
<div>
|
|
<label>Folder path</label>
|
|
<input
|
|
value={path}
|
|
onChange={(e) => updateParam('path', e.target.value)}
|
|
placeholder="/ or /sites/SiteName/Shared Documents/Folder"
|
|
/>
|
|
</div>
|
|
)}
|
|
{needsPath && ['sharepoint.readFile', 'sharepoint.uploadFile', 'sharepoint.downloadFile'].includes(nodeType) && (
|
|
<div>
|
|
<label>{nodeType === 'sharepoint.uploadFile' ? 'Target folder path' : 'Path'}</label>
|
|
<input
|
|
value={(params.path as string) ?? (params.filePath as string) ?? ''}
|
|
onChange={(e) => updateParam('path', e.target.value)}
|
|
placeholder={
|
|
nodeType === 'sharepoint.downloadFile'
|
|
? '/sites/SiteName/Shared Documents/file.pdf'
|
|
: nodeType === 'sharepoint.uploadFile'
|
|
? '/sites/.../Shared Documents/TargetFolder/'
|
|
: 'File or folder path'
|
|
}
|
|
/>
|
|
</div>
|
|
)}
|
|
{needsSiteId && (
|
|
<div>
|
|
<label>Site ID</label>
|
|
<input
|
|
value={(params.siteId as string) ?? ''}
|
|
onChange={(e) => updateParam('siteId', e.target.value)}
|
|
placeholder="SharePoint site ID"
|
|
/>
|
|
</div>
|
|
)}
|
|
{nodeType === 'sharepoint.copyFile' && (
|
|
<>
|
|
<div>
|
|
<label>Source file</label>
|
|
<input
|
|
value={(params.sourcePath as string) ?? ''}
|
|
onChange={(e) => updateParam('sourcePath', e.target.value)}
|
|
placeholder="/sites/.../folder/file.pdf"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label>Destination folder</label>
|
|
<input
|
|
value={(params.destPath as string) ?? ''}
|
|
onChange={(e) => updateParam('destPath', e.target.value)}
|
|
placeholder="/sites/.../target-folder/"
|
|
/>
|
|
</div>
|
|
{connectionId && (
|
|
<>
|
|
<details
|
|
open={copySourceExpanded}
|
|
onToggle={(e) => setCopySourceExpanded((e.target as HTMLDetailsElement).open)}
|
|
style={{
|
|
marginTop: 12,
|
|
border: '1px solid var(--border-color, #e0e0e0)',
|
|
borderRadius: 6,
|
|
background: 'var(--bg-secondary, #f8f9fa)',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<summary style={{ padding: '0.5rem 0.75rem', cursor: 'pointer', fontWeight: 500, fontSize: '0.875rem' }}>
|
|
📂 Source file durchsuchen
|
|
</summary>
|
|
<div style={{ padding: '0.5rem 0.75rem', borderTop: '1px solid var(--border-color, #e0e0e0)', maxHeight: 280, overflowY: 'auto' }}>
|
|
<SharepointBrowseTree rootPath="/" onLoadChildren={loadChildren} onSelectFile={selectSourcePath} selectedPath={(params.sourcePath as string) || null} />
|
|
</div>
|
|
</details>
|
|
<details
|
|
open={copyDestExpanded}
|
|
onToggle={(e) => setCopyDestExpanded((e.target as HTMLDetailsElement).open)}
|
|
style={{
|
|
marginTop: 8,
|
|
border: '1px solid var(--border-color, #e0e0e0)',
|
|
borderRadius: 6,
|
|
background: 'var(--bg-secondary, #f8f9fa)',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<summary style={{ padding: '0.5rem 0.75rem', cursor: 'pointer', fontWeight: 500, fontSize: '0.875rem' }}>
|
|
📂 Zielordner durchsuchen
|
|
</summary>
|
|
<div style={{ padding: '0.5rem 0.75rem', borderTop: '1px solid var(--border-color, #e0e0e0)', maxHeight: 280, overflowY: 'auto' }}>
|
|
<SharepointBrowseTree rootPath="/" onLoadChildren={loadChildren} onSelectFile={() => {}} onSelectFolder={selectDestPath} selectedPath={(params.destPath as string) || null} />
|
|
</div>
|
|
</details>
|
|
</>
|
|
)}
|
|
</>
|
|
)}
|
|
{connectionId && needsPath && hasPathInput && !['sharepoint.copyFile'].includes(nodeType) && (
|
|
<details
|
|
open={browseExpanded}
|
|
onToggle={(e) => setBrowseExpanded((e.target as HTMLDetailsElement).open)}
|
|
style={{
|
|
marginTop: 12,
|
|
border: '1px solid var(--border-color, #e0e0e0)',
|
|
borderRadius: 6,
|
|
background: 'var(--bg-secondary, #f8f9fa)',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<summary
|
|
style={{
|
|
padding: '0.5rem 0.75rem',
|
|
cursor: 'pointer',
|
|
fontWeight: 500,
|
|
fontSize: '0.875rem',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '0.5rem',
|
|
userSelect: 'none',
|
|
}}
|
|
>
|
|
<span style={{ opacity: browseExpanded ? 0.7 : 1 }}>📂</span>
|
|
SharePoint durchsuchen
|
|
</summary>
|
|
<div
|
|
style={{
|
|
padding: '0.5rem 0.75rem',
|
|
borderTop: '1px solid var(--border-color, #e0e0e0)',
|
|
maxHeight: 280,
|
|
overflowY: 'auto',
|
|
}}
|
|
>
|
|
<SharepointBrowseTree
|
|
rootPath="/"
|
|
onLoadChildren={loadChildren}
|
|
onSelectFile={selectPath}
|
|
selectedPath={path || null}
|
|
/>
|
|
</div>
|
|
</details>
|
|
)}
|
|
</>
|
|
);
|
|
};
|