Revert "[web] Add SVG support to file-view panel (#32155)" (#33832)

This reverts commit e80c491a10db6f5757c568430e17d9cbb613c5b4.

GitOrigin-RevId: dbe0de698bc7349e5b8f9712d1d13998e41ab528
This commit is contained in:
Miguel Serrano
2026-05-20 10:45:21 +02:00
committed by Copybot
parent 35681dd3b2
commit ad651a22fa
3 changed files with 11 additions and 128 deletions
@@ -1,8 +1,5 @@
import { useState, useEffect } from 'react'
import { useProjectContext } from '../../../shared/context/project-context'
import { debugConsole } from '@/utils/debugging'
import { BinaryFile } from '@/features/file-view/types/binary-file'
import useAbortController from '@/shared/hooks/use-abort-controller'
export default function FileViewImage({
file,
@@ -14,70 +11,12 @@ export default function FileViewImage({
onError: () => void
}) {
const { projectId } = useProjectContext()
const urlPath = `/project/${projectId}/blob/${file.hash}`
const extension = file.name.split('.')?.pop()?.toLowerCase()
if (extension === 'svg') {
return (
<SVGRenderer
url={urlPath}
onLoad={onLoad}
onError={onError}
alt={file.name}
/>
)
} else {
return (
<img src={urlPath} onLoad={onLoad} onError={onError} alt={file.name} />
)
}
}
type SVGRendererProps = {
url: string
alt: string
onLoad: () => void
onError: () => void
}
function SVGRenderer({ url, alt, onLoad, onError }: SVGRendererProps) {
const { signal } = useAbortController()
const [objectUrl, setObjectUrl] = useState<string | null>(null)
useEffect(() => {
let blobUrl: string | null = null
setObjectUrl(null)
fetch(url, { signal })
.then(res => {
if (!res.ok) {
throw new Error(`Error fetching SVG: ${res.statusText}`)
}
return res.arrayBuffer()
})
.then(buffer => {
const blob = new Blob([buffer], { type: 'image/svg+xml' })
blobUrl = URL.createObjectURL(blob)
setObjectUrl(blobUrl)
})
.catch(err => {
if (signal.aborted) return
debugConsole.error('Unable to render SVG', err)
onError()
})
return () => {
if (blobUrl) {
// URL.createObjectURL() allocates memory that is not garbage-collected automatically,
// we're explicitly releasing it on effect cleanup.
URL.revokeObjectURL(blobUrl)
}
}
}, [url, onError, signal])
if (!objectUrl) {
return null
}
return <img src={objectUrl} onLoad={onLoad} onError={onError} alt={alt} />
return (
<img
src={`/project/${projectId}/blob/${file.hash}`}
onLoad={onLoad}
onError={onError}
alt={file.name}
/>
)
}
@@ -9,7 +9,7 @@ import LoadingSpinner from '@/shared/components/loading-spinner'
import getMeta from '@/utils/meta'
import { BinaryFile } from '../types/binary-file'
const imageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'svg']
const imageExtensions = ['png', 'jpg', 'jpeg', 'gif']
export default function FileView({ file }: { file: BinaryFile }) {
const [contentLoading, setContentLoading] = useState(true)
@@ -1,70 +1,14 @@
import { expect } from 'chai'
import { screen, waitFor } from '@testing-library/react'
import sinon from 'sinon'
import fetchMock from 'fetch-mock'
import { screen } from '@testing-library/react'
import { renderWithEditorContext } from '../../../helpers/render-with-context'
import FileViewImage from '../../../../../frontend/js/features/file-view/components/file-view-image'
import { imageFile } from '../util/files'
import type { BinaryFile } from '@/features/file-view/types/binary-file'
const svgFile: BinaryFile<'project_file'> = {
...imageFile,
name: 'diagram.svg',
}
const svgContent =
'<svg xmlns="http://www.w3.org/2000/svg"><circle r="10"/></svg>'
describe('<FileViewImage />', function () {
beforeEach(function () {
URL.createObjectURL = sinon.stub().returns('blob:fake-url')
URL.revokeObjectURL = sinon.stub()
})
afterEach(function () {
fetchMock.removeRoutes().clearHistory()
})
it('renders a non-SVG img', function () {
it('renders an image', function () {
renderWithEditorContext(
<FileViewImage file={imageFile} onError={() => {}} onLoad={() => {}} />
)
screen.getByRole('img')
})
it('fetches and renders SVG in an img tag via blob URL', async function () {
fetchMock.get('express:/project/:project_id/blob/:hash', svgContent)
renderWithEditorContext(
<FileViewImage file={svgFile} onError={() => {}} onLoad={() => {}} />
)
await waitFor(() => {
const img = screen.getByRole('img')
expect(img.getAttribute('src')).to.equal('blob:fake-url')
})
const createObjectURLStub = URL.createObjectURL as sinon.SinonStub
expect(createObjectURLStub.calledOnce).to.be.true
const blob = createObjectURLStub.firstCall.args[0]
expect(blob).to.be.instanceOf(Blob)
expect(blob.type).to.equal('image/svg+xml')
})
it('calls onError when SVG fetch fails', async function () {
fetchMock.get('express:/project/:project_id/blob/:hash', {
throws: new Error('Network error'),
})
const onError = sinon.stub()
renderWithEditorContext(
<FileViewImage file={svgFile} onLoad={() => {}} onError={onError} />
)
await waitFor(() => {
sinon.assert.calledOnce(onError)
})
expect(screen.queryByRole('img')).to.not.exist
})
})