diff --git a/weave-js/src/common/components/FileBrowser.tsx b/weave-js/src/common/components/FileBrowser.tsx index 978e9d4b89e..82bb4d48598 100644 --- a/weave-js/src/common/components/FileBrowser.tsx +++ b/weave-js/src/common/components/FileBrowser.tsx @@ -2,7 +2,7 @@ import Tooltip from '@mui/material/Tooltip'; import * as _ from 'lodash'; import numeral from 'numeral'; import Prism from 'prismjs'; -import React, {FC, useCallback, useEffect, useRef, useState} from 'react'; +import React, {FC, memo, useCallback, useEffect, useRef, useState} from 'react'; import TimeAgo from 'react-timeago'; import {Header, Icon, Pagination, Segment, Table} from 'semantic-ui-react'; @@ -608,103 +608,107 @@ interface CodePreviewProps { language?: string; } -const CodePreview: FC = ({useLoadFile, file, language}) => { - const [data, setDataVal] = useState(''); - const [error, setErrorVal] = useState(undefined); - const ref = useRef(null); - const setData = useCallback( - (d: string) => { - // Automatically reformat JSON - let lines = d.split('\n'); - if ( - (file.name.endsWith('.json') && lines.length === 1) || - (lines.length === 2 && lines[1] === '') - ) { - try { - const parsed = JSON.parse(lines[0]); - lines = JSON.stringify(parsed, undefined, 2).split('\n'); - } catch { - // ok +const CodePreview: FC = memo( + ({useLoadFile, file, language}) => { + const [data, setDataVal] = useState(''); + const [error, setErrorVal] = useState(undefined); + const ref = useRef(null); + const setData = useCallback( + (d: string) => { + // Automatically reformat JSON + let lines = d.split('\n'); + if ( + (file.name.endsWith('.json') && lines.length === 1) || + (lines.length === 2 && lines[1] === '') + ) { + try { + const parsed = JSON.parse(lines[0]); + lines = JSON.stringify(parsed, undefined, 2).split('\n'); + } catch { + // ok + } } - } - // Truncate long lines - const truncated = lines - .map(line => { - if (line.length > 1000) { - return line.slice(0, 1000) + ' (line truncated to 1000 characters)'; - } else { - return line; - } - }) - .join('\n'); + // Truncate long lines + const truncated = lines + .map(line => { + if (line.length > 1000) { + return ( + line.slice(0, 1000) + ' (line truncated to 1000 characters)' + ); + } else { + return line; + } + }) + .join('\n'); + + setDataVal(truncated); + }, + [setDataVal, file.name] + ); + const setError = useCallback( + (errorString?: string) => + setErrorVal(errorString || 'Error loading file'), + [setErrorVal] + ); - setDataVal(truncated); - }, - [setDataVal, file.name] - ); - const setError = useCallback( - (errorString?: string) => setErrorVal(errorString || 'Error loading file'), - [setErrorVal] - ); + // We don't pass a fallback to allow dev mode zero byte files to render + const loading = useLoadFile(file, { + onSuccess: setData, + onFailure: setError, + }); - // We don't pass a fallback to allow dev mode zero byte files to render - const loading = useLoadFile(file, { - onSuccess: setData, - onFailure: setError, - }); - useEffect(() => { - if (ref.current != null) { - Prism.highlightElement(ref.current); + useEffect(() => { + if (ref.current != null) { + Prism.highlightElement(ref.current); + } + }); + + if (error != null) { + return {error}; } - }); - if (error != null) { - return {error}; - } - if (loading) { - return ; - } - // HACKING TO DISPLAY VOC - // if (file.name.endsWith('.xml')) { - // const parser = new DOMParser(); - // const xmlDoc = parser.parseFromString(data, 'text/xml'); - // const anno = xmlDoc.getElementsByTagName('annotation')[0]; - // if (anno != null) { - // for (let i = 0; i < anno.childNodes.length; i++) { - // const node = anno.childNodes[i]; - // if (node.nodeType !== Node.TEXT_NODE && node.nodeName === 'filename') { - // const filename = node.childNodes[0].textContent; - // console.log('FILE NAME', filename); - // // const imageFile = (node as any).getElementsByTagName('filename')[0]; - // // console.log('IMAGE FILE', imageFile); - // } - // console.log(node); - // } - // // anno.childNodes[] - // // console.log('VOC!'); - // } - // } - return ( -
-
;
+    }
+
+    return (
+      
- - {data} - -
-
- ); -}; + {file.sizeBytes / 1024 < 1024 ? ( + // When the file is under 1MB we use the normal code viewer with highlighting +
+            
+              {data}
+            
+          
+ ) : ( + // Use a div here because Prism seems to have global access and can apply highlighting + // whenever it wants which we don't want here. +
+ {data} +
+ )} + + ); + }, + (prevProps, nextProps) => { + return prevProps.file.url === nextProps.file.url; + } +); interface MarkdownPreviewProps { useLoadFile: UseLoadFile;