import { useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Database, Link2, LoaderCircle, Unplug } from 'lucide-react'; import { api, get, post } from '@/lib/api'; import { Badge, Button } from '@/components/ui'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; export interface ImportedTable { fileName: string; sheetName: string | null; headers: string[]; rows: string[][]; warnings: string[]; unsupportedProperties?: { name: string; type: string; reason: string }[]; } interface Connection { id: string; workspaceId: string; workspaceName: string | null; workspaceIcon: string | null; connectedAt: string; } interface Status { configured: boolean; connected: boolean; connections: Connection[]; } interface DataSource { id: string; databaseId: string | null; name: string; url: string | null; icon: string | null; } export function NotionImportSource({ disabled, onTable, }: { disabled: boolean; onTable(table: ImportedTable): void; }) { const queryClient = useQueryClient(); const [connectionId, setConnectionId] = useState(''); const [dataSourceId, setDataSourceId] = useState(''); const status = useQuery({ queryKey: ['notion-import-status'], queryFn: () => get('/api/imports/notion/status'), enabled: !disabled, }); const selectedConnection = connectionId || status.data?.connections[0]?.id || ''; const dataSources = useQuery({ queryKey: ['notion-data-sources', selectedConnection], queryFn: () => get<{ dataSources: DataSource[] }>( `/api/imports/notion/connections/${selectedConnection}/data-sources`, ), enabled: Boolean(selectedConnection), }); const connect = useMutation({ mutationFn: () => post<{ authorizationUrl: string }>('/api/imports/notion/oauth/start', {}), onSuccess: ({ authorizationUrl }) => window.location.assign(authorizationUrl), }); const materialize = useMutation({ mutationFn: () => post( `/api/imports/notion/connections/${selectedConnection}/materialize`, { dataSourceId }, ), onSuccess: onTable, }); const disconnect = useMutation({ mutationFn: (id: string) => api(`/api/imports/notion/connections/${id}`, { method: 'DELETE' }), onSuccess: () => { setConnectionId(''); setDataSourceId(''); void queryClient.invalidateQueries({ queryKey: ['notion-import-status'] }); }, }); if (status.data && !status.data.configured) { return

Notion is not configured

An operator must set the Notion OAuth environment variables and encryption key on the API server.

; } return (

Notion database

{status.data?.connected ? Connected : null}

Choose a shared data source, then map it through the same dry run as a spreadsheet.

{!status.data?.connected ? : null}
{status.data?.connected ?
: null} {connect.error || dataSources.error || materialize.error || disconnect.error ?

{errorMessage(connect.error ?? dataSources.error ?? materialize.error ?? disconnect.error)}

: null}
); } function errorMessage(error: unknown): string { return error instanceof Error ? error.message : 'The Notion request failed.'; }