Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

## Unreleased

- Example site: import jobs, and a script that clicks through the admin. `apps/payload-example` now turns the plugin's `imports` option on over a new `sources` upload collection that only a curator can read, add to, change or delete, so nobody else can fetch a source file by its address. The seed adds a job waiting to be run and one that failed on purpose, both over made-up files; a job doesn't run when it is made. Uploaded files go in a throwaway folder that is deleted when the site stops (`EXAMPLE_UPLOADS` names a folder to keep instead). The smoke test goes from 58 to 74 checks. New `pnpm click-through` builds the site, opens a Chrome already on the machine with no window and a throwaway profile, signs in as the made-up curator and does a curator's work on all four panels, 40 checks; it installs nothing, needs the network for Payload's code editor, fails on any other request off the site, and isn't in CI.
- Payload plugin: three things that script found in the real admin (changes the unreleased plugin). The panels' paragraphs and lists sat flush against each other, because the panel's margin reset outranked its spacing rule; jsdom doesn't lay out, so no test saw it. The reset now carries no weight and the import panel's status and message are spaced too. The form under a panel repeated it: a snapshot's label, id, version, checksum and counts, and an import job's message, checksums, diagnostics, warnings and progress (three of them in Payload's code editor) are now hidden in the form with `admin.hidden`, still in its data, the API and the list's columns. And the "Made-up example data" tag touched the source's title. The docs said every button asks first; running an import never did, and they now say so.
- Payload plugin: a snapshot's content is read only when it is asked for by name (changes the unreleased plugin). A stored snapshot can be 15 MB, and Payload read all of it for every list, every relationship it filled in and every admin page. Now a read, create, update or delete that names no `select` answers with every field except `snapshot`; `select: { snapshot: true }`, REST `?select[snapshot]=true` or GraphQL's `select: true` gives the content, and the export endpoint is as before. A caller's own `select` is left exactly as asked. In the admin the content field is on the new-snapshot form only: a stored snapshot's page is sent without the content and without the JSON editor, and Payload's own Save there sends the status alone. Hosts' code that read `doc.snapshot` from a plain read, or from the document an after-read or after-change hook is given, has to select it. The lock on sealed content doesn't depend on this. Fixed on the way: the admin panels showed the old status after Payload's own Save; they now read from the site again whenever Payload reports the document saved. Tested: 10 new tests (8 on a real Payload with an in-memory MongoDB, one of them over HTTP, and 2 in jsdom), 3 new checks over HTTP in the example site (58 in all), and five deliberate breaks, each caught. Also run in headless Chrome on the example site, outside CI: a stored snapshot's page has no content and no editor, a sealed snapshot pasted into the new-snapshot form is stored with the same checksum, and Payload's Save sends one small request. Not explained: in that run, after a snapshot was made through the form and its page loaded again, Payload's read-only Counts group showed no fields under its heading; four shorter runs of the same steps drew them. Not tested: Postgres, SQLite, a browser with a window. See [ADR 0012](docs/architecture/adr/0012-payload-plugin.md), point 17.
- Payload plugin, part 5 of M7: admin panels (still not on npm). Each of the plugin's four collections gets a panel at the top of its edit page, on unless `admin: { panels: false }`. The snapshot panel says the status in words, what the snapshot holds (counts, a line per classification and phylogeny, sources with their licenses) and, for one made by accepting a proposal, which proposal and the two sealed person ids; a manager gets Publish and Withdraw. The view panel draws the saved view (the first 200 nodes) with the same tree as an outline for the keyboard and the lines readers are told, and holds Publish, with the reason, until the form is saved and the snapshot is published. The import panel shows the steps of a run, its warnings and diagnostics, looks again every 3 seconds while a job runs, and offers to run a queued, failed or interrupted job. The proposal panel says what a proposal would change, and a manager accepts it (naming the new version) or declines it. Every button asks first in the page and says what can't be undone; accepting lists what gets sealed for good and asks the manager to check it for personal details. The panels have no powers of their own: they call the host's site from the browser as the signed-in person, so the host's `access` callbacks decide, and a refusal reads "Nothing was changed." with the site's reason. New: the `@captiveorigins/payload-plugin-onetaxonomy/client` entry (found through Payload's import map, so run `payload generate:importmap` after adding the plugin), the `admin.panels` option, and one endpoint, `GET /api/<snapshots>/:id/summary` (and `summarizeSnapshot`), which answers counts and capped lists, never names or trees, with the same 404 as the other endpoints. For a snapshot made from a proposal it gives the name the host shows for each sealed id to signed-in requesters only, looked up per request and never stored. `@payloadcms/ui` and `react` are new optional peer dependencies, and the plugin now depends on `@captiveorigins/onetaxonomy-react` for the drawing. Colours come from Payload's theme variables; a test reads the installed `@payloadcms/ui` stylesheets and checks text at 4.5:1 and control edges at 3:1 in light and dark, and a status is never colour alone. The example site shows the panels to its curator and turns Payload's Gravatar avatar off. Tested: 94 new tests (74 render the panels in jsdom with Payload's hooks and `fetch` replaced by stand-ins, 11 on the stylesheet, 9 on the summary against a real Payload with an in-memory MongoDB), and 8 new checks over HTTP in the example site (55 in all). The snapshot, view and proposal panels were also clicked through once in headless Chrome on the example site, in light and dark; that run is not in CI. Not tested: the import panel in a real admin, a screen reader, Safari, Firefox, a phone, or a custom Payload theme. Found on the way and written in the README: Payload's own admin loads its JSON editor from cdn.jsdelivr.net and, unless `admin.avatar` is `'default'`, asks gravatar.com with a hash of the signed-in person's email address. See [ADR 0012](docs/architecture/adr/0012-payload-plugin.md), point 16.
- Payload plugin, part 5 of M7: admin panels (still not on npm). Each of the plugin's four collections gets a panel at the top of its edit page, on unless `admin: { panels: false }`. The snapshot panel says the status in words, what the snapshot holds (counts, a line per classification and phylogeny, sources with their licenses) and, for one made by accepting a proposal, which proposal and the two sealed person ids; a manager gets Publish and Withdraw. The view panel draws the saved view (the first 200 nodes) with the same tree as an outline for the keyboard and the lines readers are told, and holds Publish, with the reason, until the form is saved and the snapshot is published. The import panel shows the steps of a run, its warnings and diagnostics, looks again every 3 seconds while a job runs, and offers to run a queued, failed or interrupted job. The proposal panel says what a proposal would change, and a manager accepts it (naming the new version) or declines it. Publish, Withdraw, Accept and Decline ask first in the page and say what can't be undone (running an import doesn't ask: it stores at most a staged snapshot); accepting lists what gets sealed for good and asks the manager to check it for personal details. The panels have no powers of their own: they call the host's site from the browser as the signed-in person, so the host's `access` callbacks decide, and a refusal reads "Nothing was changed." with the site's reason. New: the `@captiveorigins/payload-plugin-onetaxonomy/client` entry (found through Payload's import map, so run `payload generate:importmap` after adding the plugin), the `admin.panels` option, and one endpoint, `GET /api/<snapshots>/:id/summary` (and `summarizeSnapshot`), which answers counts and capped lists, never names or trees, with the same 404 as the other endpoints. For a snapshot made from a proposal it gives the name the host shows for each sealed id to signed-in requesters only, looked up per request and never stored. `@payloadcms/ui` and `react` are new optional peer dependencies, and the plugin now depends on `@captiveorigins/onetaxonomy-react` for the drawing. Colours come from Payload's theme variables; a test reads the installed `@payloadcms/ui` stylesheets and checks text at 4.5:1 and control edges at 3:1 in light and dark, and a status is never colour alone. The example site shows the panels to its curator and turns Payload's Gravatar avatar off. Tested: 94 new tests (74 render the panels in jsdom with Payload's hooks and `fetch` replaced by stand-ins, 11 on the stylesheet, 9 on the summary against a real Payload with an in-memory MongoDB), and 8 new checks over HTTP in the example site (55 in all). The snapshot, view and proposal panels were also clicked through once in headless Chrome on the example site, in light and dark; that run is not in CI. Not tested: the import panel in a real admin, a screen reader, Safari, Firefox, a phone, or a custom Payload theme. Found on the way and written in the README: Payload's own admin loads its JSON editor from cdn.jsdelivr.net and, unless `admin.avatar` is `'default'`, asks gravatar.com with a hash of the signed-in person's email address. See [ADR 0012](docs/architecture/adr/0012-payload-plugin.md), point 16.
- Benchmarks: frame times in a browser. `apps/playground/bench.html` (built with the playground) pans, zooms and scrolls made-up trees of 125 to 10,000 tips as SVG and on the canvas and times every frame; open it in any browser, press Run and save the numbers. `node scripts/bench-browser.mjs` runs it in the Chrome already installed, headless, at pixel density 1 and 2 and with the main thread slowed 4 times, and writes `docs/benchmarks-browser.md`; `--from <file>` adds a section from numbers saved in another browser. It uses a throwaway profile that it deletes, listens on this machine only and sends nothing anywhere. First numbers (headless Chrome 157, M2 Max, other work running): the canvas held 60 frames a second at every size up to 19,999 nodes, slowed thread included; SVG held it through 1,999 nodes, and through 499 on the slowed thread. A second section is from a headless build of WebKit 27.2 (Playwright's: the engine Safari and the Mac app use, but neither program), driven by hand as the doc describes, at normal speed only: the canvas held 60 frames a second at every size, and SVG held it through 1,999 nodes. When a browser's clock ticks in whole milliseconds, as WebKit's does, the script says so in the section and prints no decimal places. The 1,000-node switch is unchanged. Not measured: Safari itself, the Mac app's web view, Firefox, a window on a real screen, a real slow device, radial layouts. The benchmark page and script have no tests of their own.
- Payload plugin docs: moving a departed person's proposals to another account. The README's "When someone leaves" now says that `author` and `decidedBy` can't be changed through Payload, that the lock is a hook and so doesn't cover a host's own database code, and that a host making that move there must change only those two fields and leave `proposal`, `checksum` and the snapshot alone. A new test makes the move on MongoDB and checks that the proposal still matches its checksum, the version made from it still verifies, and the proposal stays locked. No code changed; an option to allow the move through Payload was considered and not built (ADR 0012).
- Payload plugin: people are recorded by id, never by name (changes the unreleased proposals, before anyone used them). `proposals.nameOf` is gone. `proposals.personId({ req })` gives an opaque id for the signed-in person (default: their user document's id), and that id is all a proposal stores about its author and all an accepted proposal seals into the new snapshot for the author and the manager. An id is 1 to 64 letters, digits, `.`, `_`, `:` and `-`, starting with a letter or digit, so an email address or a name with a space in it is refused: the action stops, nothing is saved, and the refused value isn't written to the log. A one-word handle would pass; the plugin can't tell it from an id. `proposals.displayName({ req, personId })` is optional and gives the name to show: it is looked up each time a proposal is read (once per person per request), returned as `authorName` on the proposal and in the preview, and never stored or sealed, so a name changed or removed at the site changes what is shown at once and leaves every snapshot's checksum alone. Why: a name inside a sealed snapshot can't be taken out when a person leaves. Core is unchanged apart from its comments and one error text: `acceptIntoSnapshot` still seals the `author` and `acceptedBy` strings it is given. Still sealed as written, and not screened: a proposal's title, each move's note and the manager's note. No endpoint turns an id from a snapshot's record back into a name. Tested on Payload 3.93 with an in-memory MongoDB (142 plugin tests, 526 in all) and through the example site (47 checks); eight deliberate breaks of the new code each failed a test. Not tested: Postgres or SQLite, and a host with more than one auth collection.
Expand Down
1 change: 1 addition & 0 deletions apps/payload-example/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.next/
next-env.d.ts
tsconfig.tsbuildinfo
.uploads/
Loading
Loading