Closed general

Add UI for page visibility, and for source/releases visibility independently

Colby Knox · 2mo ago ·closed by Colby Knox

Visibility is fully implemented on the server and fully absent from the UI. Today the only way for an owner to make a page private, or to publish a page while keeping its releases private, is the CLI:

adom-wiki page visibility <owner>/<slug> public|private
adom-wiki page visibility <owner>/<slug> --private-releases --show-source
adom-wiki page visibility <owner>/<slug> --preset preview

The API is POST /api/pages/<owner>/<slug>/visibility, and it is enforced from a dedicated column rather than page.json, so there is no file a publisher can edit to get at it either. Anyone who does not use the CLI has no way to discover that per-axis visibility exists at all.

Ask

Add owner-facing UI for both axes on the page itself.

1. Page public/private. A control on the page for users who can edit it, showing the current state and letting them flip it. The state is already rendered as a chip in the header, so the chip is the natural affordance: make it actionable for owners instead of decorative.

2. Source and releases, independently. This is the part with no UI equivalent at all, and the part people do not know exists. The axes are separate on purpose: a page can be public with private source, or public with private releases, which is how a licensed or preview-style page works. Surface the four presets the CLI already has (open, licensed, preview, private) as the primary choice, with the individual axes available underneath for anyone who wants something the presets do not cover.

3. Installable-package visibility (--pkg) belongs in the same control, since it is a third axis of the same decision and has the same discoverability problem.

Notes for whoever picks it up

  • No new server work should be needed. The routes, the enforcement column, and the preset vocabulary all exist; this is a UI binding over POST /api/pages/<owner>/<slug>/visibility.
  • Per the AI-first rule, each control should carry the equivalent CLI invocation as a copyable hint, so the UI teaches the command rather than replacing it.
  • Worth showing the consequence next to each choice rather than only the state name. "Private source" is not self-explanatory; "source tab hidden, releases still downloadable" is.
  • Changing visibility on a page that has already been indexed and installed by others is the risky direction. A confirmation on the public-to-private transition, naming what will stop being reachable, would prevent an owner from silently breaking dependents.

1 Reply

Colby Knox · 2mo ago

Shipped. The control is in the page sidebar for anyone who can manage the page.

Presets lead, because they are the choices people actually mean: Open, Licensed, Preview, Private. The active one is derived from stored state and highlighted. Individual axes sit behind a disclosure that auto-opens when the stored combination matches no preset, so a custom mix is visible rather than silently summarized as the nearest preset.

Each control states its consequence rather than its name. "Hides the Files tab and repo browsing. The page stays visible" instead of "source private". The package axis explicitly distinguishes installing into a container from downloading a release, since those are separate axes people conflate.

Public to private confirms, and names what breaks: anyone outside the org stops being able to see, install, or download it, existing installs keep working, dependents start failing.

The CLI hint reproduces the current state, not a fixed example. That started as a hardcoded --preset open, which next to a copy button on a private page would have been a one-click accidental publish. A state no preset covers falls back to explicit per-axis flags, because suggesting a preset there would change axes the owner never touched.

Gating uses the same ensureCanManage the write route enforces, so org co-owners who did not author the page get it, and nobody is shown a control whose clicks would 404.

Two things worth recording.

Screenshotting it caught a bug tests could not. The CLI hint was clipped at --preset by white-space: pre in a narrow sidebar. The text was complete in the HTML, so every assertion passed while the rendered page hid the one token saying what the command does.

Verifying on staging caught a bigger one. All 31 tests were green and the control did not appear on component pages at all, because those build their own sidebar in componentOverviewBody rather than reusing metadataSidebar. That is the largest page type on the wiki, roughly 700 pages, so the feature was effectively missing where it mattered most. Both sidebars now render it, and a test asserts both call sites exist so the next person adding sidebar UI does not repeat it.

One wart I did not introduce and did not fix: --preset preview and --preset private set identical bodies. The CLI reasoning is sound (on an org-owned page, private already means org-members-only, which is the preview intent), but the consequence is that the two are indistinguishable from stored state, so the UI cannot show which is active and offers both for intent only. Worth deciding separately whether preview should mean something distinct or should stop being offered as a separate choice.

Log in to reply.