import React, { useState, useEffect, useRef } from 'react'; import { IconLoader2, IconFileImport } from '@tabler/icons'; import { toastError } from 'utils/common/error'; import Modal from 'components/Modal'; import jsyaml from 'js-yaml'; import { postmanToBruno, isPostmanCollection } from 'utils/importers/postman-collection'; import { convertInsomniaToBruno, isInsomniaCollection } from 'utils/importers/insomnia-collection'; import { convertOpenapiToBruno, isOpenApiSpec } from 'utils/importers/openapi-collection'; import { processBrunoCollection } from 'utils/importers/bruno-collection'; const convertFileToObject = async (file) => { const text = await file.text(); try { if (file.type === 'application/json' || file.name.endsWith('.json')) { return JSON.parse(text); } const parsed = jsyaml.load(text); if (typeof parsed !== 'object' || parsed === null) { throw new Error(); } return parsed; } catch { throw new Error('Failed to parse the file – ensure it is valid JSON or YAML'); } }; const FullscreenLoader = ({ isLoading }) => { const [loadingMessage, setLoadingMessage] = useState(''); // Messages to cycle through while loading const loadingMessages = [ 'Processing collection...', 'Analyzing requests...', 'Translating scripts...', 'Preparing collection...', 'Almost done...' ]; useEffect(() => { if (!isLoading) return; let messageIndex = 0; const interval = setInterval(() => { messageIndex = (messageIndex + 1) % loadingMessages.length; setLoadingMessage(loadingMessages[messageIndex]); }, 2000); setLoadingMessage(loadingMessages[0]); return () => clearInterval(interval); }, [isLoading]); return (

{loadingMessage}

This may take a moment depending on the collection size

); }; const ImportCollection = ({ onClose, handleSubmit }) => { const [isLoading, setIsLoading] = useState(false); const [dragActive, setDragActive] = useState(false); const fileInputRef = useRef(null); const handleDrag = (e) => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer) { e.dataTransfer.dropEffect = 'copy'; } if (e.type === 'dragenter' || e.type === 'dragover') { setDragActive(true); } else if (e.type === 'dragleave') { setDragActive(false); } }; const processFile = async (file) => { setIsLoading(true); try { const data = await convertFileToObject(file); if (!data) { throw new Error('Failed to parse file content'); } let collection; if (isPostmanCollection(data)) { collection = await postmanToBruno(data); } else if (isInsomniaCollection(data)) { collection = convertInsomniaToBruno(data); } else if (isOpenApiSpec(data)) { collection = convertOpenapiToBruno(data); } else { collection = await processBrunoCollection(data); } handleSubmit({ collection }); } catch (err) { toastError(err, 'Import collection failed'); } finally { setIsLoading(false); } }; const handleDrop = async (e) => { e.preventDefault(); e.stopPropagation(); setDragActive(false); if (e.dataTransfer.files && e.dataTransfer.files[0]) { await processFile(e.dataTransfer.files[0]); } }; const handleBrowseFiles = () => { fileInputRef.current.click(); }; const handleFileInputChange = async (e) => { if (e.target.files && e.target.files[0]) { await processFile(e.target.files[0]); } }; if (isLoading) { return ; } const acceptedFileTypes = [ '.json', '.yaml', '.yml', 'application/json', 'application/yaml', 'application/x-yaml' ] return (

Import from file

Drop file to import or{' '}

Supports Bruno, Postman, Insomnia, and OpenAPI v3 formats

); }; export default ImportCollection;