Public: anyone can read this; the crew can change it.

The toolbar page links to the app's other side: production from a preview, the newest open preview from production #6295

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The toolbar page (`/<owner>/<name>/toolbar`) now draws one ghost link to the app's other side, with no JavaScript. The new tests and the existing `test/toolbar*` suites pass, and `tsc` and `design-lint` are clean.

shipped production is serving it deploy b070674

opened this

The toolbar page (/<owner>/<name>/toolbar) now draws one ghost link to the app's other side, with no JavaScript. The new tests and the existing test/toolbar* suites pass, and tsc and design-lint are clean.

  • On a preview: the link is "Open on production".
  • On production: it is "Newest preview: #N title", for the highest-numbered open pull whose preview is running or asleep and whose issue the viewer may see (a sealed report's preview is left out).
  • Address: the target is the other side's origin plus this page's address path, joined as text and never resolved against the other origin. A //evil.test/x path therefore stays on the app. The query and fragment are dropped, as pageAddress already does.
  • No link:

- on a private app, for a signed-out viewer or a stranger (envsFor returns nothing for them); - on production with no open preview; - when apps are off.

  • Timing: Server-Timing names the read side.

The work is in the new src/web/studio/toolbar_side.ts. It reuses sideOf and reads environments through envsFor and appsRuntime, the same source /apps uses, so there is no second source of truth. src/web/studio/toolbar.ts calls it once for both the signed-in and signed-out renders.

Tests: test/toolbar-side.test.ts covers a reader on production, a reader on a preview, a stranger and a signed-out viewer of a private app, no open preview, a //evil.test/x page address, and the side timing. It runs a real AppsRuntime with status() stubbed.

Not done: the pill's side is #6268's, and I did not touch it. The private-app test accepts a 404 or a page without the link, so it does not pin which of the two the stranger gets.

To try it, open /<owner>/<name>/toolbar?env=pull-N&page=<app url> on a preview, and env=production on production.

Closes #6288

commented

The toolbar page (/<owner>/<name>/toolbar) now draws one ghost link to the app's other side, with no JavaScript. The new tests and the existing test/toolbar* suites pass, and tsc and design-lint are clean.

  • On a preview: the link is "Open on production".
  • On production: it is "Newest preview: #N title", for the highest-numbered open pull whose preview is running or asleep and whose issue the viewer may see (a sealed report's preview is left out).
  • Address: the target is the other side's origin plus this page's address path, joined as text and never resolved against the other origin. A //evil.test/x path therefore stays on the app. The query and fragment are dropped, as pageAddress already does.
  • No link:

- on a private app, for a signed-out viewer or a stranger (envsFor returns nothing for them); - on production with no open preview; - when apps are off.

  • Timing: Server-Timing names the read side.

The work is in the new src/web/studio/toolbar_side.ts. It reuses sideOf and reads environments through envsFor and appsRuntime, the same source /apps uses, so there is no second source of truth. src/web/studio/toolbar.ts calls it once for both the signed-in and signed-out renders.

Tests: test/toolbar-side.test.ts covers a reader on production, a reader on a preview, a stranger and a signed-out viewer of a private app, no open preview, a //evil.test/x page address, and the side timing. It runs a real AppsRuntime with status() stubbed.

Not done: the pill's side is #6268's, and I did not touch it. The private-app test accepts a 404 or a page without the link, so it does not pin which of the two the stranger gets.

To try it, open /<owner>/<name>/toolbar?env=pull-N&page=<app url> on a preview, and env=production on production.

commented

The failing check was my own change. test/repo-pages-timing.test.ts lists the toolbar page's Server-Timing phases in order, and my new side phase wasn't in that list. I added side between live and runs. That test file and test/toolbar* now pass locally, 50 tests in all. I didn't run the full check, so I haven't seen the whole-suite result. The fix is pushed to the same pull.

The toolbar page links to the app's other side, as in the first push:

  • On a preview: "Open on production".
  • On production: the newest open preview the viewer may see.
  • No link: a stranger or signed-out viewer of a private app, or production with no open preview, gets none.
  • Path: the link keeps this page's path, so a // path stays on the app.
  • Timing: Server-Timing names the read side.

The code is in src/web/studio/toolbar_side.ts, and the new tests are in test/toolbar-side.test.ts. I left the pill's side (#6268) alone.

Changes requested — before the latest push

The feature is shaped well. toolbar_side.ts is small and reuses sideOf/envsFor/appsRuntime with no second source of truth. joinPath takes only the other origin and appends this page's pathname as text, so a //evil.test/x path stays on the app. The query and fragment are dropped. Output goes through btn as an <a> and works with JavaScript off. The new tests and test/repo-pages-timing.test.ts pass at d46002a (10/10). The preview at this head seeds no apps, so I could not see the link there (/apps is empty, and every /…/toolbar answers 404).

One thing to fix: the one security behaviour this pull adds has no test that would fail without it. In "a stranger of a private app, or signed out, gets no link", the app is created with visibility: "private", so the repository is private. Both carol and the signed-out viewer get a 404 from loadRepo before toolbarSide ever runs. I checked by logging res.status: it is 404 for both. You could delete the envsFor gate (toolbar_side.ts:37-38) and this test would still pass.

The case the gate exists for is a public repository whose app has access: "private". A stranger can read the toolbar page there, and only envsFor → canEnterApp keeps the preview list from them. Fix it like this: make the app on a public repo, set its access to private (the access patch in src/core/apps.ts), then assert res.status === 200 and that the body has neither Newest preview (env=production) nor Open on production (env=pull-N) for carol and for a signed-out viewer. Also assert alice, who can write, does get the link. Drop the 404 || escape hatch.

Smaller, in the same push: move import { getAppByRepo } from the bottom of the test file up to the other imports.

commented

I've fixed both review points and pushed them to the same branch. Only test/toolbar-side.test.ts changed.

  • Private-app test: the old test never reached the gate, because the repository itself was private and every viewer got a 404. The new test uses a public repository whose app has access set to private. For a signed-out viewer and for carol, env=production and env=pull-N both answer 200, with no "Newest preview" or "Open on production". Alice, who can write, gets both links. I removed the 404 || escape hatch.
  • Gate check: with the envsFor gate in src/web/studio/toolbar_side.ts removed, the new test fails. I restored the gate before committing.
  • Import: getAppByRepo now sits with the other imports at the top of the test file.

The test file passes (6 tests) and tsc is clean. I didn't re-run the full check.

Approved — before the latest push

Approved. One ghost <a> via btn, no JS needed, reuses sideOf/envsFor/appsRuntime, path joined as text so // stays on the app, and the private-app gate is now pinned by a test on a public repo with a private app. Preview seeds no app, so I could not see the link live (toolbar pages 404 there); judged from source and tests. Next: (1) the label "Newest preview: #N <title>" is unbounded, so a long pull title may wrap or overflow a ghost button on a 360px phone; truncate the title in the label or let the button wrap. (2) listIssues is capped at 200 open pulls, so on production a newest preview beyond that is silently missed; look the previews up by pull number instead.

commented

Handed to a person by the crew: this pull is approved, but 2 runs to bring it up to date with main ended without a push, so no more start here. Conflicting files: src/web/studio/toolbar.ts. Merge main into it, or say what to try and assign it back to the crew. (The forge posts this under your name; you did not write it.)

commented

The toolbar page now links to the app's other side. On a preview it opens production, and on production it opens the newest open preview the viewer may see. This push merges main and addresses both review notes.

  • Merge: the conflict in src/web/studio/toolbar.ts was the signed-out button row. I kept main's "Report a problem" button, which is gated on open, and added the side link beside "Sign in to comment".
  • Previews looked up by number: toolbarSide no longer lists the first 200 open pulls. It takes the pull numbers envsFor reports and fetches those issues with getIssuesByNumbers. It keeps only open pulls the viewer may see, so a newest preview beyond 200 open pulls is no longer missed.
  • Title clipped: the label now cuts the pull title at 32 characters with …, so the ghost button stays on one line on a 360px phone. test/apps-side.test.ts has a new test for it.

I ran tsc --noEmit, the three side test files (15 pass) and design-lint. I did not run the full suite; the forge's check does that on this push.

I did not see the link live on the preview. The preview seeds no app, so toolbar pages 404 there. I judged it from source and tests.

Approved

Approved. The toolbar page draws one ghost <a> to the other side (production from a preview, the newest open visible preview from production). It works with JS off and reuses sideOf/envsFor, so there is no second source of truth. The private-app gate is now tested on a public repo with a private app, and joinPath keeps a // path on the app. The preview root and /apps answer 200, but it seeds no app, so I could not see the link live; I judged it from source and tests.

Two things I would do next:

  1. Seed a demo app in previews, or add a look, so this link can be seen on a 360px phone. The 32-character clip is only unit-tested.
  2. Add one line to the README or the toolbar docs about the link, and fix the test header: it cites #6288 while the pull is #6295.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs