@@ -15,10 +15,11 @@ export const HtmlFileRenderer: React.FC<HtmlFileRendererProps> = ({
1515 isInlineHtml = false ,
1616 htmlContent : inlineHtmlContent
1717} ) => {
18- const [ isExpanded , setIsExpanded ] = useState < boolean > ( false ) ;
18+ const [ isExpanded , setIsExpanded ] = useState < boolean > ( true ) ;
1919 const [ htmlContent , setHtmlContent ] = useState < string > ( inlineHtmlContent || '' ) ;
2020 const [ isLoading , setIsLoading ] = useState < boolean > ( false ) ;
2121 const [ error , setError ] = useState < string > ( '' ) ;
22+ const [ fileExists , setFileExists ] = useState < boolean | null > ( null ) ;
2223
2324 const cleanFilePath = ( path : string ) : string => {
2425 // For inline HTML, return a descriptive name
@@ -36,14 +37,57 @@ export const HtmlFileRenderer: React.FC<HtmlFileRendererProps> = ({
3637 return cleaned ;
3738 } ;
3839
40+ const checkFileExists = async ( ) => {
41+ // For inline HTML, file always "exists"
42+ if ( isInlineHtml && inlineHtmlContent ) {
43+ setFileExists ( true ) ;
44+ return ;
45+ }
46+
47+ try {
48+ const cleanPath = cleanFilePath ( filePath ) ;
49+ console . log ( 'Checking if HTML file exists:' , cleanPath ) ;
50+
51+ // Use a simple GET request to check if file exists
52+ // We'll abort quickly to avoid downloading large files
53+ const controller = new AbortController ( ) ;
54+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 3000 ) ; // 3 second timeout
55+
56+ const response = await fetch ( `/api/load-html-file?path=${ encodeURIComponent ( cleanPath ) } ` , {
57+ signal : controller . signal
58+ } ) ;
59+
60+ clearTimeout ( timeoutId ) ;
61+
62+ if ( response . ok ) {
63+ setFileExists ( true ) ;
64+ } else if ( response . status === 404 ) {
65+ console . log ( `File does not exist: ${ cleanPath } (404 Not Found)` ) ;
66+ setFileExists ( false ) ;
67+ } else {
68+ console . log ( `File check failed: ${ cleanPath } (${ response . status } )` ) ;
69+ setFileExists ( false ) ;
70+ }
71+ } catch ( err : any ) {
72+ // If it's an abort error, still check - might just be slow
73+ if ( err . name === 'AbortError' ) {
74+ console . log ( `File check timed out, assuming file exists: ${ filePath } ` ) ;
75+ setFileExists ( true ) ;
76+ } else {
77+ console . log ( `Error checking file existence: ${ err . message } ` ) ;
78+ setFileExists ( false ) ;
79+ }
80+ }
81+ } ;
82+
3983 const loadHtmlContent = async ( ) => {
4084 // If it's inline HTML, content is already provided
4185 if ( isInlineHtml && inlineHtmlContent ) {
4286 setHtmlContent ( inlineHtmlContent ) ;
4387 return ;
4488 }
4589
46- if ( isExpanded && ! htmlContent && ! error ) {
90+ if ( isExpanded && ! htmlContent && ! error && fileExists ) {
4791 setIsLoading ( true ) ;
4892 setError ( '' ) ;
4993
@@ -69,10 +113,38 @@ export const HtmlFileRenderer: React.FC<HtmlFileRendererProps> = ({
69113 } ;
70114
71115 useEffect ( ( ) => {
72- if ( isExpanded ) {
116+ // First check if file exists
117+ checkFileExists ( ) ;
118+ } , [ filePath , isInlineHtml , inlineHtmlContent ] ) ;
119+
120+ useEffect ( ( ) => {
121+ // Only load content if file exists and component is expanded
122+ if ( isExpanded && fileExists ) {
73123 loadHtmlContent ( ) ;
74124 }
75- } , [ isExpanded , filePath , isInlineHtml , inlineHtmlContent ] ) ;
125+ } , [ isExpanded , fileExists ] ) ;
126+
127+ // Don't render the component if file doesn't exist
128+ if ( fileExists === false ) {
129+ return null ;
130+ }
131+
132+ // Show loading state while checking file existence
133+ if ( fileExists === null ) {
134+ return (
135+ < div className = "my-4 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden" >
136+ < div className = "bg-gradient-to-r from-green-50 to-blue-50 dark:from-green-900/20 dark:to-blue-900/20 px-4 py-3" >
137+ < div className = "flex items-center gap-3" >
138+ < IconFile size = { 20 } className = "text-green-600 dark:text-green-400" />
139+ < div className = "animate-pulse" >
140+ < div className = "h-4 bg-gray-300 dark:bg-gray-600 rounded w-32 mb-2" > </ div >
141+ < div className = "h-3 bg-gray-200 dark:bg-gray-700 rounded w-48" > </ div >
142+ </ div >
143+ </ div >
144+ </ div >
145+ </ div >
146+ ) ;
147+ }
76148
77149 const openInSystemBrowser = ( ) => {
78150 if ( isInlineHtml ) {
@@ -145,7 +217,7 @@ export const HtmlFileRenderer: React.FC<HtmlFileRendererProps> = ({
145217 { isInlineHtml ? 'Inline HTML' : 'HTML Plot' }
146218 </ span >
147219 < span className = "text-xs text-gray-500 dark:text-gray-400" >
148- { isInlineHtml ? 'HTML response content' : 'Interactive Bokeh visualization' }
220+ { isInlineHtml ? 'HTML response content' : 'Interactive visualization' }
149221 </ span >
150222 </ div >
151223 </ div >
0 commit comments