HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/agentcloud/webapp/src/components/DatasourceTable.tsx
import * as API from '@api';
import { Menu, Transition } from '@headlessui/react';
import {
	ArrowPathIcon,
	Cog6ToothIcon,
	DocumentIcon,
	EllipsisHorizontalIcon,
	PlayIcon,
	TrashIcon,
} from '@heroicons/react/20/solid';
import ButtonSpinner from 'components/ButtonSpinner';
import DatasourceStatusIndicator from 'components/DatasourceStatusIndicator'; // Update this path as necessary
import { useAccountContext } from 'context/account';
import { useNotificationContext } from 'context/notifications';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { Fragment, useReducer,useState } from 'react';
import { toast } from 'react-toastify';
import { DatasourceStatus,datasourceStatusColors } from 'struct/datasource';
import submittingReducer from 'utils/submittingreducer';

export default function DatasourceTable({ datasources, fetchDatasources }: { datasources: any[], fetchDatasources?: any }) {

	const [notificationContext, refreshNotificationContext]: any = useNotificationContext();
	const [accountContext]: any = useAccountContext();
	const { account, csrf } = accountContext as any;
	const router = useRouter();
	const { resourceSlug } = router.query;
	const [syncing, setSyncing] = useReducer(submittingReducer, {});
	const [deleting, setDeleting] = useReducer(submittingReducer, {});
	const [deletingMap, setDeletingMap] = useState({});
	
	async function deleteDatasource(datasourceId) {
		setDeleting({ [datasourceId]: true });
		try {
			await API.deleteDatasource({
				_csrf: csrf,
				resourceSlug,
				datasourceId,
			}, async () => {
				setDeletingMap(oldMap => {
					oldMap[datasourceId] = true;
					return oldMap;
				});
				await new Promise(res => setTimeout(res, 700));
				fetchDatasources();
				setDeletingMap(oldMap => {
					delete oldMap[datasourceId];
					return oldMap;
				});
			}, () => {
				toast.error('Error deleting datasource');
			}, router);
		} finally {
			setDeleting({ [datasourceId]: false });
		}
	}

	async function syncDatasource(datasourceId) {
		setSyncing({ [datasourceId]: true });
		try {
			await API.syncDatasource({
				_csrf: csrf,
				resourceSlug,
				datasourceId,
			}, () => {
				fetchDatasources();
			}, () => {
				toast.error('Error syncing');
			}, router);
		} finally {
			setSyncing({ [datasourceId]: false });
		}
	}

	return (

		<div className='rounded-lg overflow-hidden shadow overflow-x-auto'>
			<table className='min-w-full divide-y divide-gray-200 dark:!border-slate-700'>
				<thead className='bg-gray-50 dark:bg-slate-800 dark:!border-slate-700'>
					<tr>
						<th scope='col' className='px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-white'>
							Type
						</th>
						<th scope='col' className='px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-white'>
							Name
						</th>
						<th scope='col' className='px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-white'>
							Status
						</th>
						<th scope='col' className='px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-white'>
							Schedule Type
						</th>
						<th scope='col' className='px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-white'>
							Last Synced
						</th>
						<th scope='col' className='px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase dark:text-white'>
							Date Uploaded
						</th>
						<th scope='col' className='px-6 py-3 w-20 text-right text-xs font-medium text-gray-500 uppercase dark:text-white'>
							Actions
						</th>
					</tr>
				</thead>
				<tbody className='bg-white divide-y divide-gray-200 dark:bg-slate-800'>
					{datasources.map((datasource) => {
						const processingOrEmbedding = [DatasourceStatus.PROCESSING, DatasourceStatus.EMBEDDING].includes(datasource?.status);
						return (
							<tr key={datasource._id} className={`cursor-pointer hover:bg-gray-50 dark:hover:bg-slate-700 dark:text-white dark:!border-slate-700 transition-all opacity-1 duration-700 ${deletingMap[datasource._id] ? 'bg-red-400' : 'cursor-pointer hover:bg-gray-50'}`} style={{ borderColor: deletingMap[datasource._id] ? 'red' : '' }}>
								<td className='px-6 py-3 whitespace-nowrap flex items-center' onClick={() => router.push(`/${resourceSlug}/datasource/${datasource._id}`)}>
									<img src={`https://connectors.airbyte.com/files/metadata/airbyte/source-${datasource.sourceType}/latest/icon.svg`} className='w-6 me-1.5' />
									<span className='px-2 inline-flex text-sm leading-6 rounded-full capitalize'>
					                    {datasource.sourceType}
									</span>
								</td>
								<td className='px-6 py-3 whitespace-nowrap' onClick={() => router.push(`/${resourceSlug}/datasource/${datasource._id}`)}>
									<div className='flex items-center'>
										<div className='text-sm font-medium text-gray-900 dark:text-white'>{datasource.name}</div>
									</div>
								</td>
								<td className='px-6 py-3 whitespace-nowrap' onClick={() => router.push(`/${resourceSlug}/datasource/${datasource._id}`)}>
									<DatasourceStatusIndicator datasource={datasource} processingOrEmbedding={processingOrEmbedding} />
								</td>
								<td className='px-6 py-3 whitespace-nowrap' onClick={() => router.push(`/${resourceSlug}/datasource/${datasource._id}`)}>
									<span className='px-2 inline-flex text-sm leading-5 rounded-full capitalize'>
										{datasource?.connectionSettings?.scheduleType || '-'}
									</span>
								</td>
								<td className='px-6 py-3 whitespace-nowrap' onClick={() => router.push(`/${resourceSlug}/datasource/${datasource._id}`)}>
									<div className='text-sm text-gray-900 dark:text-white' suppressHydrationWarning>
										{datasource.sourceType === 'file' ? 'N/A' : (datasource.lastSyncedDate ? new Date(datasource.lastSyncedDate).toLocaleString() : 'Never')}
									</div>
								</td>
								<td className='px-6 py-3 whitespace-nowrap' onClick={() => router.push(`/${resourceSlug}/datasource/${datasource._id}`)}>
									<span suppressHydrationWarning className='text-sm text-gray-900 dark:text-white'>
										{new Date(datasource.createdDate).toLocaleString()}
									</span>
								</td>
								<td className='px-6 py-5 whitespace-nowrap text-right text-sm font-medium flex justify-end space-x-5 items-center'>
									{datasource.sourceType !== 'file' && <button
										onClick={() => syncDatasource(datasource._id)}
										disabled={syncing[datasource._id]
											|| deleting[datasource._id]
											|| (datasource.status === DatasourceStatus.DRAFT && !datasource?.connectionSettings?.syncCatalog?.streams?.length)
											|| [DatasourceStatus.PROCESSING, DatasourceStatus.EMBEDDING].includes(datasource.status)}
										className='rounded-md disabled:bg-slate-400 bg-indigo-600 px-2 -my-1 py-1 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 dark:text-white'
									>
									
										{syncing[datasource._id] && <ButtonSpinner size={14} className='ms-2 -me-1' />}
										{syncing[datasource._id] ? 'Syncing...' : 'Sync Now'}
									</button>}
									{/*<a href={`/${resourceSlug}/datasource/${datasource._id}`} className='text-gray-500 hover:text-gray-700'>
										<Cog6ToothIcon className='h-5 w-5' aria-hidden='true' />
									</a>*/}
									<button
										onClick={(e) => {
											e.preventDefault();
											e.stopPropagation();
											deleteDatasource(datasource._id);
										}}
			                        	className='text-red-500 hover:text-red-700'
			                        	disabled={deleting[datasource._id]}
			                        >
										{deleting[datasource._id] ? <ButtonSpinner size={14} /> : <TrashIcon className='h-5' aria-hidden='true' />}
			                        </button>
			                    </td>
							</tr>
						);
					})}
				</tbody>
			</table>
		</div>

	);
}