[26.2/33] A file's history, seen: the panel, the administrator's list, and one reader for text - #417
Merged
Conversation
The engine that keeps what a save replaces, and the API that reads a history
back, arrived with the batch before this one. Nothing showed them: no mark in a
listing, no panel, no way for an administrator to see what histories cost, and
no way to read an earlier version at all.
This is that half.
A file that has earlier versions carries a small mark in the listing, with how
many; clicking it opens the panel, which lists what was kept, who saved it and
where it came from, and offers reading a version, downloading it, putting it
back, naming it, pinning it and deleting it. Putting one back keeps what it
replaced, so nothing is lost by going back. The mark is counted once per folder
rather than once per row, and a preference turns it off — which takes the query
away as well as the icon.
An administrator gets the list of every file that has a history, wherever it
is, with what each one takes up, and can empty one. Those routes are addressed
by the history's own id rather than by a path, because the ones worth finding
include files that no longer exist: a history whose file was deleted outside
the application has no path left to ask about, and no file to authorise
against. They sit behind the administrator check for the same reason.
Reading text is now one reader, used by the editor, by a version and by a file
still in the trash — the two the batch before this one left out. That reader
fixes what the editor used to do with it:
- A UTF-16 file was answered "this file appears to be binary and cannot be
opened". In UTF-16 every letter of English is accompanied by a zero byte,
and a zero byte was exactly the test for binary. That is what `Out-File`
wrote by default until PowerShell 6 and what Notepad still offers as
"Unicode", so an export or a log from a Windows machine could not be
opened. A mark is believed when there is one; otherwise the pairing of
zeros decides, which is what tools that write UTF-16 without a mark leave
behind.
- A save wrote UTF-8 over whatever the file was. That reads perfectly well
here and breaks whatever wrote it, so a save now writes back in the
encoding the file already had.
- The size limit was checked when opening and not when saving: a paste larger
than the limit was written, and the file could then never be opened again.
It is now checked on the bytes about to be written, which in UTF-16 are
twice the characters.
- The editor opens two megabytes and saves through a JSON body, whose limit
was Express's own default of 100 kB. A file between the two opened and
could never be saved, answered "request entity too large" — which names
neither limit. The two are one decision now: the body limit is derived from
what the editor may open, and a body limit somebody set is a ceiling that
is never raised from here, so it is the editor that gives way.
The editor's read is also a GET the browser may keep and revalidate, answered
304 while the file is unchanged, so opening the editor from the Markdown
preview no longer downloads the same file twice. The identity is taken from the
file's metadata, including the inode — a save writes a new file and renames it
over the old one, so a save that comes out the same size within one clock tick
still differs.
An earlier version and a file in the trash open in the editor as text to read:
no save, no shortcut that saves, and an editor that does not take typing.
Closing goes back where it came from — the folder with the history open again,
or the trash, inside the deleted folder the file was read from.
Found while wiring this up: `marksForFolder`, `listFilesWithVersions`,
`readFileVersions` and `deleteFileVersions` all called store helpers that were
never added. Nothing called them, so nothing noticed; all four threw. The
queries they need are here, and every one of them now has a test.
Left for later, and named here so it is not lost: taking a version out as a new
file somewhere, and putting one over another file, both need the destination
dialog, which is not here yet; reading a version of an office document needs
the office editors to accept one, which comes with the batch that finishes
them; and the entry an activity log would want for a purge waits for the log.
Gates: lint and formatting on the changed files, `npm run build`, every backend
module loads, and the whole backend suite — 1,949 pass, against the two that
fail on `main` before any of this. Every claim above has a test that fails when
the change behind it is put back; the detection of UTF-16 was mutated twice,
once for the mark and once for the pairing, because they are two mechanisms.
The screens were checked in the built image: two saves, the mark showing 2 in
the listing, the panel opening from it, a version read in the read-only viewer,
a version restored from the panel with the history growing to three, a file
deleted and read from the trash by double-clicking it, and the administrator's
list showing the file, its space and its history. That is also how the last
defect here turned up: the dialog that confirms a restore teleports to the body
and stacked below the panel's own overlay, so its buttons could not be clicked.
No unit test would have seen it.
This was referenced Sep 26, 2026
Merged
Which keys are preferences was decided twice: once in the settings service, which sanitises the value, and once in the settings route, which decides whether the key is written at all. They had drifted. The preference added here — the mark on files that have versions — reached the service's list and not the route's, so the toggle moved on screen, the save answered success, and nothing was stored. It would have read as "my setting does not stick", with two lists to find before anyone could say why. One list now, named and exported by the service; the route asks it. A test walks every key the service calls a preference and checks the route keeps it, so the two cannot drift again.
cerede2000
pushed a commit
to cerede2000/NextExplorer
that referenced
this pull request
Sep 26, 2026
The plan's own rule is that a batch carries its documentation. The trash landed in nxzai#405 and nxzai#416, file versions in nxzai#406 and nxzai#417, and neither brought a page: there is nothing under `docs/` that describes either, so the retention settings, what a restore keeps, who sees what in the trash and how versions are thinned are all readable only in the source. Two new pages, and nine existing ones brought up to what the application now does — the environment reference gains the variables the last twenty batches added, the feature and workflow pages gain the trash, versions, archives and search index, and the sidebar gains the two new entries in both of its shapes. Both pages were trimmed to what `main` has, rather than copied. Three things are deliberately left out and travel with the batch that brings them: - restoring to a folder of your choosing. `POST /api/trash/restore` accepts a destination, but nothing on the screen offers one and `restoreTrashItems` does not send one, so the page would describe an action nobody can reach. - `COPY_PRESERVE_PERMISSIONS`, `PREVIEW_MAX_RENDER_SIZE`, `BULK_DELETE_CONCURRENCY`, `MAX_BROWSABLE_ARCHIVE_SIZE`, `ARCHIVE_CACHE_MAX_SIZE`, `UPLOAD_CHUNKED_AUTO_FALLBACK` and the six `PERFORMANCE_DIAGNOSTICS_*` — twelve rows for variables the configuration does not read yet. - recent destinations, per-folder preferences and the inline quick-actions menu. ## Checks `npm run docs:build` — and it is worth saying that it was failing before this last pass: three links pointed at an installation page that only exists in the fork, and vitepress treats a dead link as an error. Every internal link in the eleven pages was resolved against the tree, which is how those turned up. `npm run format:check` reports the same 22 files as `main` does on its own; the eleven pages and the config are clean. `npm run build` and the backend module load both pass, untouched by a documentation batch.
vikramsoni2
pushed a commit
that referenced
this pull request
Sep 26, 2026
The plan's own rule is that a batch carries its documentation. The trash landed in #405 and #416, file versions in #406 and #417, and neither brought a page: there is nothing under `docs/` that describes either, so the retention settings, what a restore keeps, who sees what in the trash and how versions are thinned are all readable only in the source. Two new pages, and nine existing ones brought up to what the application now does — the environment reference gains the variables the last twenty batches added, the feature and workflow pages gain the trash, versions, archives and search index, and the sidebar gains the two new entries in both of its shapes. Both pages were trimmed to what `main` has, rather than copied. Three things are deliberately left out and travel with the batch that brings them: - restoring to a folder of your choosing. `POST /api/trash/restore` accepts a destination, but nothing on the screen offers one and `restoreTrashItems` does not send one, so the page would describe an action nobody can reach. - `COPY_PRESERVE_PERMISSIONS`, `PREVIEW_MAX_RENDER_SIZE`, `BULK_DELETE_CONCURRENCY`, `MAX_BROWSABLE_ARCHIVE_SIZE`, `ARCHIVE_CACHE_MAX_SIZE`, `UPLOAD_CHUNKED_AUTO_FALLBACK` and the six `PERFORMANCE_DIAGNOSTICS_*` — twelve rows for variables the configuration does not read yet. - recent destinations, per-folder preferences and the inline quick-actions menu. ## Checks `npm run docs:build` — and it is worth saying that it was failing before this last pass: three links pointed at an installation page that only exists in the fork, and vitepress treats a dead link as an error. Every internal link in the eleven pages was resolved against the tree, which is how those turned up. `npm run format:check` reports the same 22 files as `main` does on its own; the eleven pages and the config are clean. `npm run build` and the backend module load both pass, untouched by a documentation batch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The second half of batch 26. #415 made a file's history real and readable through the API; nothing showed it. This is the panel, the administrator's list, and reading text wherever it lives.
What this adds
A history you can see. A file with earlier versions carries a small mark in the listing, with how many. Clicking it opens the panel: what was kept, who saved it, where it came from, and — per version — read, download, restore, name, pin, delete. Restoring keeps what it replaced, so going back loses nothing. The mark is counted once per folder rather than once per row, and a user preference turns it off, which takes the query away as well as the icon.
An administrator's view. Every file that has a history, wherever it is, with what it takes up; a history can be emptied from there. Those routes name a history by its own id rather than by a path: the ones worth finding include files that no longer exist, and a history whose file was deleted outside the application has no path to ask about and no file to authorise against. They sit behind
ensureAdminfor the same reason.One reader for text. The editor, a version and a file still in the trash now read through the same service — the last two are what #415 and #416 left out.
Defects fixed on the way
All four live in the editor's own read and save path, which this batch owns.
Out-Filewrote by default until PowerShell 6 and what Notepad still offers as "Unicode": an export or a log from a Windows machine could not be opened at all. A mark is believed when there is one; otherwise the pairing of zeros decides, which is what tools writing UTF-16 without a mark leave behind.And one found while wiring the panel up:
marksForFolder,listFilesWithVersions,readFileVersionsanddeleteFileVersionsall called store helpers that were never added. Nothing called those four, so nothing noticed; all of them threw. The queries are here, and each has a test.Also: the editor's read is now a GET the browser keeps and revalidates, answered 304 while the file is unchanged — so opening the editor from the Markdown preview stops downloading the same file twice. The identity includes the inode, because a save writes a new file and renames it over the old one.
Left for later, deliberately
Gates
npm run build; every backend module loads.mainbefore any of this (auth.test.js,browse-hidden-files.test.js— measured onmainitself, not assumed).Independent of the stack; applies on current
main.