This is an automated email from the ASF dual-hosted git repository. jdaugherty pushed a commit to branch fixVulnerabilitiesAndModernize in repository https://gitbox.apache.org/repos/asf/grails-forge-ui.git
commit fcffc4cf0afdaaaded20c0113a1b96228968e6a9 Author: James Daugherty <[email protected]> AuthorDate: Sun Mar 1 01:24:29 2026 -0500 Fix files with no content, fix files that are not previewable (null), fix selection on initial dialog load --- .../src/components/CodePreview/CodePreview.jsx | 48 ++++++++++++++-------- .../src/components/CodePreview/code-preview.css | 6 +++ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/app/launch/src/components/CodePreview/CodePreview.jsx b/app/launch/src/components/CodePreview/CodePreview.jsx index 6319b2e..a5251c1 100644 --- a/app/launch/src/components/CodePreview/CodePreview.jsx +++ b/app/launch/src/components/CodePreview/CodePreview.jsx @@ -62,6 +62,11 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { path: null, }) + const { defaultSelected, defaultExpanded } = useMemo( + () => extractDefaults(showing), + [showing] + ) + const shareLink = useMemo(() => { let link = fullyQualifySharableLink(sharable, { [ACTIVITY_KEY]: PREVIEW_ACTIVITY, @@ -104,6 +109,9 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { language = 'bash' } setCurrentFile({ contents, language, path }) + } else { + // File cannot be previewed (null or object contents) + setCurrentFile({ contents: null, language: null, path }) } } @@ -114,24 +122,21 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { } } - const parts = path.split('/') + // nodeIds in renderTree are built as `/${key}` so prefix with / + const fullPath = path.startsWith('/') ? path : '/' + path + const parts = fullPath.split('/').filter((i) => i) const defaultExpanded = [] - while (parts.length) { - defaultExpanded.push(parts.join('/')) - parts.pop() + // Build expanded paths from root down (e.g. /src, /src/main, /src/main/groovy) + for (let i = 1; i <= parts.length; i++) { + defaultExpanded.push('/' + parts.slice(0, i).join('/')) } return { - defaultSelected: path, + defaultSelected: fullPath, defaultExpanded, } } - - const { defaultSelected, defaultExpanded } = useMemo( - () => extractDefaults(showing), - [showing] - ) - - useEffect(() => { + + useEffect(() => { if (typeof showing !== 'string') { return } @@ -143,7 +148,8 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { contents = contents[key] } if (key && contents) { - handleFileSelection(key, contents, showing) + const nodeId = showing.startsWith('/') ? showing : '/' + showing + handleFileSelection(key, contents, nodeId) } }, [preview, showing]) @@ -166,11 +172,15 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { .map((key) => { const children = nodes[key] const nodeId = `${rootKey}/${key}` + const isFile = typeof children === 'string' + const isFolder = typeof children === 'object' && children !== null + const className = isFile || isFolder ? '' : 'non-previewable' return ( <TreeItem key={nodeId} nodeId={nodeId} label={key} + className={className} onClick={() => handleFileSelection(key, children, nodeId)} > {renderTree(children, nodeId)} @@ -217,7 +227,7 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { style={{ borderRight: '1px solid' }} > <TreeView - key={defaultSelected} + key={`${defaultSelected}-${Object.keys(preview).length}`} defaultCollapseIcon={<Icon>folder_open</Icon>} defaultExpandIcon={<Icon>folder</Icon>} defaultEndIcon={<Icon>description</Icon>} @@ -228,7 +238,7 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { </TreeView> </Grid> <Grid item xs={9} className={'grid-column'}> - {currentFile.contents && ( + {currentFile.contents ? ( <SyntaxHighlighter className="codePreview" language={currentFile.language} @@ -237,7 +247,13 @@ const CodePreview = ({ theme = 'light', disabled, onLoad, onClose }, ref) => { > {currentFile.contents} </SyntaxHighlighter> - )} + ) : currentFile.path ? ( + <div style={{ padding: '16px', color: '#999' }}> + {currentFile.contents === '' + ? 'This file has no content.' + : 'This file cannot be previewed.'} + </div> + ) : null} </Grid> </Grid> </DialogContent> diff --git a/app/launch/src/components/CodePreview/code-preview.css b/app/launch/src/components/CodePreview/code-preview.css index 29d537f..fffe860 100644 --- a/app/launch/src/components/CodePreview/code-preview.css +++ b/app/launch/src/components/CodePreview/code-preview.css @@ -6,6 +6,12 @@ min-width: max-content; } +/* Files that cannot be previewed */ +.non-previewable { + color: #888 !important; + font-style: italic; +} + .code-preview.footer-wrapper { display: flex; flex-direction: row;
