fix(editor): reclaim the nine formats DSH has no preview for
The alpha.1 handover refused 27 extensions so DSH's own document preview could own them, but nine of those have NO host renderer at all: `avif` and `ods` sit in `document/unviewable.ts`'s "known binary, no renderer" list and get the unsupported empty state directly, while `xlsb` / `xlt` / `xltx` / `xltm` / `ots` / `dot` / `dotx` fall through to the plain-text body, fail the binary check and land on the same dead end. Before that handover these files reached the plugin's `code` catch-all and rendered the binary-download pane, so refusing them was a user-visible regression we introduced ourselves — and rc.1 did not restore it. They are claimed again (`fods` stays handed over: the host shows that flat XML as plain text, which beats a download pane). `canOpen` had zero test coverage, which is exactly why the regression went unnoticed, so `tests/native-surface.spec.ts` now pins both directions: every format the host renders must be refused, every format it cannot render must be claimed. Reverting to the old list makes it fail with `macro.xlsb: expected false to be true`.
This commit is contained in:
@@ -49,16 +49,25 @@ import {
|
||||
*
|
||||
* Refusing here is what hands the address over: `canOpen` returning false
|
||||
* leaves the built-in `text` type (the `fallback` band) as the only claimant.
|
||||
*
|
||||
* The list is exactly the set the host renders — nothing more. Nine extensions
|
||||
* that the host has NO renderer for (`xlsb xlt xltx xltm ots dot dotx avif`)
|
||||
* used to be refused here too, and refusing them turned "the plugin shows a
|
||||
* download panel" into "the host shows 'preview is not available for this file
|
||||
* type yet'" — a dead end. They are claimed again, so the `code` catch-all
|
||||
* takes them to the binary download pane. `fods` stays refused on purpose: the
|
||||
* host's plain-text fallback renders flat ODS XML, which beats a download.
|
||||
* `tests/native-surface.spec.ts` pins both directions of this boundary.
|
||||
*/
|
||||
const HOST_OWNED_EXTS: ReadonlySet<string> = new Set([
|
||||
// Spreadsheets: the built-in renders a table in a worker.
|
||||
'xlsx', 'xls', 'xlsb', 'xlt', 'xltx', 'xltm', 'ods', 'ots', 'fods', 'csv', 'tsv',
|
||||
'xlsx', 'xls', 'csv', 'tsv', 'fods',
|
||||
// PDF: the built-in viewer pages and zooms.
|
||||
'pdf',
|
||||
// Images: the built-in viewer adds a zoom viewport.
|
||||
'png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp', 'ico', 'avif',
|
||||
'png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp', 'ico',
|
||||
// Office documents: the built-in converts them to PDF host-side.
|
||||
'doc', 'docx', 'dot', 'dotx', 'ppt', 'pptx',
|
||||
'doc', 'docx', 'ppt', 'pptx',
|
||||
])
|
||||
|
||||
/**
|
||||
|
||||
@@ -326,6 +326,70 @@ describe('registerNativeSurface lifecycle (service-driven registration)', () =>
|
||||
|
||||
dispose()
|
||||
})
|
||||
|
||||
it('claims exactly the extensions DSH has no preview for (the nine restored formats included)', () => {
|
||||
// DSH 0.1.7 handed every read-only preview to `ui-sidebar-documentpreview`,
|
||||
// and `canOpen` returning false is what gives the address away. The host's
|
||||
// renderer tables cover xlsx/xls/csv/tsv, pdf, the eight common image
|
||||
// formats, doc/docx/ppt/pptx and the flat-ODS text fallback — nine
|
||||
// extensions that were refused here as well have NO host renderer at all,
|
||||
// and refusing them swapped the plugin's binary-download pane for the
|
||||
// host's "Preview is not available for this file type yet" dead end. This
|
||||
// pins both directions so the refusal list can never drift wider than the
|
||||
// host again; the host files behind the boundary are named in
|
||||
// src/client/native/index.ts.
|
||||
const store = createSidebarStore()
|
||||
store.setSession('s1')
|
||||
const service = createBetterSidebarService(store)
|
||||
service.registerTab({ id: 'editor', title: 'Files', component: () => null })
|
||||
const records = createNativeTabRecords()
|
||||
let canOpen: ((address: string) => boolean) | undefined
|
||||
const ctx = {
|
||||
inject: (_deps: readonly string[], callback: (injected: { get: () => unknown }) => void) => {
|
||||
callback({
|
||||
get: () => ({
|
||||
register: (definition: { kind: string; canOpen?: (address: string) => boolean }) => {
|
||||
if (definition.kind === 'editor') canOpen = definition.canOpen
|
||||
return () => {}
|
||||
},
|
||||
}),
|
||||
})
|
||||
return { dispose: () => {} }
|
||||
},
|
||||
get: () => undefined,
|
||||
slots: { inject: (_key: string, callback: () => () => void) => callback(), register: () => () => {} },
|
||||
}
|
||||
registerNativeSurface({ ctx: ctx as never, store, service, records })
|
||||
expect(canOpen, 'the editor type registered no canOpen').toBeTypeOf('function')
|
||||
const open = canOpen as (address: string) => boolean
|
||||
|
||||
/** One session-scoped file address, the shape the chat hands the sidebar. */
|
||||
const file = (name: string) => `dsh-resource://file/session/s1/${name}`
|
||||
|
||||
// Formats the host renders: DSH's own preview must own them.
|
||||
for (const name of [
|
||||
'book.xlsx', 'legacy.xls', 'data.csv', 'data.tsv', 'flat.fods',
|
||||
'paper.pdf', 'photo.png', 'photo.jpg', 'anim.gif', 'photo.webp', 'art.svg',
|
||||
'tile.bmp', 'favicon.ico', 'report.docx', 'report.doc', 'deck.pptx', 'deck.ppt',
|
||||
]) {
|
||||
expect(open(file(name)), name).toBe(false)
|
||||
}
|
||||
|
||||
// Formats the host has NO renderer for: the plugin claims them, so the
|
||||
// `code` catch-all reaches the binary-download pane instead of a dead end.
|
||||
for (const name of [
|
||||
'macro.xlsb', 'sheet.xlt', 'template.xltx', 'macro.xltm',
|
||||
'flat.ods', 'flat.ots', 'notes.dot', 'notes.dotx', 'next.avif',
|
||||
]) {
|
||||
expect(open(file(name)), name).toBe(true)
|
||||
}
|
||||
|
||||
// The three viewers the plugin keeps on purpose, and a non-file address.
|
||||
for (const name of ['README.md', 'page.html', 'main.ts']) {
|
||||
expect(open(file(name)), name).toBe(true)
|
||||
}
|
||||
expect(open('sidebar://editor')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('NativeTabBody full-height host wrapper', () => {
|
||||
|
||||
Reference in New Issue
Block a user