import {FormEvent, useEffect, useMemo, useRef, useState} from 'react' import {Code2, Database, Play, Plus, RefreshCw, Table2, Trash2, type LucideIcon} from 'lucide-react' import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import {JsonRecordModal} from '@/components/JsonRecordModal' import {useAccountId} from '@/lib/accountStore' import { createCosmosContainer, deleteCosmosContainer, deleteCosmosItem, listCosmosContainers, listCosmosItems, queryCosmosItems, upsertCosmosItem, } from '@/api/cloudProxyClient' import type {CloudProvider} from '@/types/cloud' import type {CloudResource, CosmosItem} from '@/types/resource' interface CosmosNoSqlPanelProps { cloud: CloudProvider resource?: CloudResource runtimeReachable: boolean selectedContainerId?: string onSelectContainer: (id: string | undefined) => void } export function CosmosNoSqlPanel({cloud, resource, runtimeReachable, selectedContainerId, onSelectContainer}: CosmosNoSqlPanelProps) { const qc = useQueryClient() const accountId = useAccountId() const selectionChanged = useRef(false) const databaseId = resource?.id const [containerName, setContainerName] = useState('') const [partitionKeyPath, setPartitionKeyPath] = useState('/id') const [documentText, setDocumentText] = useState('{\n "id": ""\n}') const [documentError, setDocumentError] = useState(null) const [selectedItem, setSelectedItem] = useState() const [addRecordOpen, setAddRecordOpen] = useState(false) const [sql, setSql] = useState('SELECT * FROM c') const [confirmContainer, setConfirmContainer] = useState(null) const [confirmItem, setConfirmItem] = useState(null) const containersKey = useMemo(() => ['cosmos-containers', accountId, cloud, databaseId], [accountId, cloud, databaseId]) const itemsKey = useMemo(() => ['cosmos-items', accountId, cloud, databaseId, selectedContainerId], [accountId, cloud, databaseId, selectedContainerId]) const containersQuery = useQuery({ queryKey: containersKey, queryFn: ({signal}) => listCosmosContainers(cloud, databaseId ?? '', signal), enabled: Boolean(databaseId) && runtimeReachable, }) const containers = containersQuery.data ?? [] const selectedContainer = containers.find((container) => container.id === selectedContainerId) const itemsQuery = useQuery({ queryKey: itemsKey, queryFn: ({signal}) => listCosmosItems(cloud, databaseId ?? '', selectedContainerId ?? '', signal), enabled: Boolean(databaseId && selectedContainer) && runtimeReachable, }) const createContainerMut = useMutation({ mutationFn: () => createCosmosContainer(cloud, databaseId ?? '', {containerName, partitionKeyPath}), onSuccess: () => { void qc.invalidateQueries({queryKey: containersKey}) }, }) const deleteContainerMut = useMutation({ mutationFn: (containerId: string) => deleteCosmosContainer(cloud, databaseId ?? '', containerId), onSuccess: () => { void qc.invalidateQueries({queryKey: containersKey}) }, }) const upsertItemMut = useMutation({ mutationFn: (document: Record) => upsertCosmosItem(cloud, databaseId ?? '', selectedContainerId ?? '', document), onSuccess: (item) => { setAddRecordOpen(false) setSelectedItem(item) setDocumentError(null) setDocumentText(JSON.stringify(item.document, null, 2)) void qc.invalidateQueries({queryKey: itemsKey}) }, }) const deleteItemMut = useMutation({ mutationFn: (item: CosmosItem) => deleteCosmosItem(cloud, databaseId ?? '', selectedContainerId ?? '', item.id, item.partitionKey), onSuccess: (_, item) => { if (selectedItem?.id === item.id) resetDocumentEditor() setConfirmItem(null) void qc.invalidateQueries({queryKey: itemsKey}) }, }) const queryMut = useMutation({ mutationFn: (input: {containerId: string; query: string}) => queryCosmosItems(cloud, databaseId ?? '', input.containerId, input.query), }) const saveError = documentError ?? (upsertItemMut.error instanceof Error ? upsertItemMut.error.message : null) const activeQueryResult = queryMut.variables?.containerId === selectedContainerId ? queryMut.data : undefined useEffect(() => { setSelectedItem(undefined) setAddRecordOpen(false) setDocumentText('{\n "id": ""\n}') setDocumentError(null) setSql('SELECT * FROM c') }, [cloud, databaseId]) useEffect(() => { setSelectedItem(undefined) setAddRecordOpen(false) setDocumentText('{\n "id": ""\n}') setDocumentError(null) }, [selectedContainerId]) if (cloud !== 'azure') return null if (!databaseId) { return (

Select a Cosmos database

Containers, documents, and SQL queries are loaded after a database is selected.

) } function submitContainer(event: FormEvent) { event.preventDefault() if (!containerName.trim()) return createContainerMut.mutate(undefined, { onSuccess: (container) => { if (selectionChanged.current) return onSelectContainer(container.id) setContainerName('') setPartitionKeyPath('/id') }, }) } function submitDocument(event: FormEvent) { event.preventDefault() try { const parsed = JSON.parse(documentText) as unknown if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { setDocumentError('Document must be a JSON object.') return } if (!('id' in parsed) || !String((parsed as Record).id ?? '').trim()) { setDocumentError('Document id is required.') return } setDocumentError(null) upsertItemMut.mutate(parsed as Record) } catch (error) { setDocumentError(error instanceof Error ? error.message : 'Invalid JSON document.') } } return (
setContainerName(event.target.value)} placeholder="Container name" disabled={!runtimeReachable}/> setPartitionKeyPath(event.target.value)} placeholder="/id" disabled={!runtimeReachable}/>
{createContainerMut.error instanceof Error &&
{createContainerMut.error.message}
} {containersQuery.error instanceof Error &&
{containersQuery.error.message}
}
{containersQuery.isLoading &&
Loading containers
} {containersQuery.isSuccess && containers.length === 0 &&
No containers
} {containersQuery.isSuccess && selectedContainerId && !selectedContainer &&
Container not found: {selectedContainerId}
} {containers.map((container) => ( ))}
{itemsQuery.error instanceof Error &&
{itemsQuery.error.message}
} {deleteItemMut.error instanceof Error &&
{deleteItemMut.error.message}
}
{(itemsQuery.data ?? []).map((item) => ( ))}
Id Updated ETag
selectItem(item)}>{item.id} selectItem(item)}>{formatValue(item.timestamp)} selectItem(item)}>{formatShort(item.etag)} {confirmItem === item.id ? ( ) : ( )}
{!selectedContainerId &&

Select a container

Documents are scoped to a Cosmos container.

} {itemsQuery.isLoading &&
Loading documents
} {selectedContainerId && itemsQuery.isSuccess && itemsQuery.data.length === 0 &&

No documents

Create a JSON document or run a query after data exists.

}
{selectedItem ? (