Repository navigation
feat(reef): make the providers rail vertical tabs with an All providers entry - #2552
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 11 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Contributor
Author
|
Reel
A rerun of both now passes (5 of 5). The Postgres variant has not run. |
… the code they retired Remove exactFilter and Table.VirtualTail, which only the old rail used, and the AGENTS.md rule that pointed to exactFilter.
AlbertQM
force-pushed
the
reef/providers-vertical-tabs
branch
from
October 20, 2026 13:03
266f690 to
7f877fd
Compare
iaptsiauri
added a commit
that referenced
this pull request
Oct 21, 2026
…one (#2580) ## Summary An agent could call `createProvider` with an OAuth Provider Configuration that names no OAuth application, for a service Coral cannot register one with (no Dynamic Client Registration or Client ID Metadata Document, such as Google), or for device authorization. Coral returned `needs_sign_in`. The person's sign-in then failed, and Reef showed only "Coral is not available." `createProvider` now refuses the call, and the agent can correct it: ```diff createProvider prepare Setup, confirm Provider Configuration SetupPublishability Coral → publish + Person, and the sign-in has no OAuth application + → end the Setup + → invalid_input at `authentication.client`: + "Coral cannot register an OAuth application with this service; + register one with the service and give its `client_id`" Person → needs_sign_in + Reef link ``` ```text has_oauth_application(authentication) oauth_authorization_code without client → can Coral set one up for this Setup? oauth_device_code without client → no (Coral never sets one up) anything else → yes ``` An older Coral server can still confirm such a configuration. Reef handles that case: ```diff attemptProgress stage + confirmed configuration, OAuth sign-in not started, no application, + and Coral cannot set one up → configuration <AccountStep> - <Button "Sign in with …" disabled={pending}> + <Button "Sign in with …" disabled={pending || no application}> <ManagementErrorBoundary> - any other status → "Coral is unavailable. Reload the page to try again." + 400 / 409 with a body → Reef's reason + other 4xx → "Coral cannot complete this request. Go back to the previous page." + 5xx → "Coral is unavailable. Reload the page to try again." ``` The configuration hint now reads "Enter the client ID of your OAuth application in configuration before you sign in." `isOAuthMethod` and `automaticApplicationAllowed` replace four inline copies of those checks in Reef. `TestModules::accounts()` replaces four copies of the filesystem-vault setup in the `coral-run` tests. ## Evidence The new tests ran against `main`'s source (tests from this branch), then against this branch: - **Before:** `cargo test -p coral-run --lib an_invalid_argument_names_what_to_correct` fails. The OAuth case with no client returns `{"status": "needs_sign_in", "url": "…/providers/new?setup=…"}`, not `invalid_input`. **After:** passes for both the authorization-code case and the device-code case. Each denial also asserts it published nothing and canceled every Setup it prepared. - **Before:** Reef Vitest fails 9 cases: - `model.test.ts`: the agent's link for an MCP, API or device sign-in Coral cannot set up opens `discovery` / `operations`, not `configuration` - `account-step.test.tsx`: "Sign in with Gmail" is enabled for the shared account and for your own account - `management-error.test.tsx`: a 400 or 409 shows "Coral is unavailable" - `oauth-application.test.tsx`: the old hint copy **After:** all 66 cases in those four files pass. - Gates on this branch, rebased on `main`: - Rust: `make rust-checks` passes, 1469 of 1469 (6 skipped). - Reef: `npm run check`, `typecheck`, `npm test` (1644 + 661 pass) and `build` pass. `test:server` has 15 pass and 1 fail, in `scripts/bundle-server.test.mjs` (`'hello bundle'` vs `'hello staged'`). This PR does not touch that file. #2552 reported the same failure. - Not run: `make postgres-tests`. No repository code changes. ## Merge Danger **Door:** two-way No schema, stored data or API shape changes. Revert restores the old `needs_sign_in` answer. **Blast Radius:** provider-setup Agents that call `createProvider` with OAuth and no `client` for a service without automatic registration now get `invalid_input`, not a Reef link. That link led to a sign-in that could not start. Management pages that end in a 4xx other than 401, 403 or 404 now say the request failed, not that Coral is unavailable. --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
simonwhitaker
pushed a commit
that referenced
this pull request
Oct 22, 2026
🤖 I have created a release *beep* *boop* --- ## [1.2.0](v1.1.0...v1.2.0) (2026-10-22) ### Features * **activity:** record authored source locations for calls and outputs ([#2535](#2535)) ([2d735ca](2d735ca)) * **activity:** show persistent Program source beside selected records ([#2569](#2569)) ([f403819](f403819)) * add the Claude recipe and read gzipped OpenAPI documents ([#2513](#2513)) ([07c27a2](07c27a2)) * **catalog:** share named TypeScript types across a Provider ([#2482](#2482)) ([256e37d](256e37d)) * **desktop:** run the runtime on a Postgres database named in desktop.json ([#2485](#2485)) ([96465a0](96465a0)) * **functions:** type coral.providers, coral.workspace and coral.functions at Saved Function save ([#2526](#2526)) ([a465850](a465850)) * **provider:** create the Coral Built-in Provider at coral.workspace in every new Workspace ([#2349](#2349)) ([06e65ca](06e65ca)) * **provider:** store an agent's createProvider request on its Setup ([#2593](#2593)) ([92847d2](92847d2)) * **provider:** update every Workspace's Built-in Provider catalog at boot ([#2355](#2355)) ([24615d9](24615d9)) * **reef:** add NextDNS provider recipe ([#2509](#2509)) ([e44880e](e44880e)) * **reef:** calmer providers table and a flush app shell ([#2462](#2462)) ([ffe279c](ffe279c)) * **reef:** improve the UI on small screens ([#2531](#2531)) ([75e020a](75e020a)) * **reef:** make the providers rail vertical tabs with an All providers entry ([#2552](#2552)) ([08d007a](08d007a)) * **reef:** providers page UI tweaks ([#2562](#2562)) ([7ca218e](7ca218e)) * **reef:** put the list pages' main action back in the top bar as a primary button ([#2546](#2546)) ([761ea6d](761ea6d)) * **reef:** read ^, $ and * in every filter field ([#2520](#2520)) ([d322356](d322356)) * **reef:** refuse a provider display name another provider uses ([#2518](#2518)) ([fdcd473](fdcd473)) * **reef:** review provider configuration changes in a dialog ([#2579](#2579)) ([24417e9](24417e9)) * **reef:** show search indexing failures on a Provider and its Operations ([#2504](#2504)) ([6cffed0](6cffed0)) * **reef:** show your recent activity summary on the workspace overview ([#2574](#2574)) ([0d1dba5](0d1dba5)) * **reef:** title list pages in their toolbar, with the main action beside it ([#2525](#2525)) ([fd44b72](fd44b72)) * **reef:** UI tweaks to provider's page ([#2566](#2566)) ([62204ca](62204ca)) * **reef:** unify Activity detail panels and action reviews ([#2544](#2544)) ([409d062](409d062)) * return only declared successes from Operation calls ([#2517](#2517)) ([0270bf1](0270bf1)) * **run:** enforce the Fan-out Limit inside the Run Owner ([#2571](#2571)) ([cb53419](cb53419)) * **run:** introduce the Run Owner for Program requests ([#2524](#2524)) ([245d19d](245d19d)) * **run:** let coral.workspace.createProvider configure and publish the Provider itself ([#2352](#2352)) ([088faaf](088faaf)) * **run:** let createProvider configure sign-in and link to Reef's sign-in step ([#2353](#2353)) ([8d5495c](8d5495c)) * **run:** list a workspace's providers with coral.workspace.listProviders ([#2374](#2374)) ([179c43a](179c43a)) * **run:** make the Run Owner survive uncertain commits and lost leases ([#2541](#2541)) ([3a1fad1](3a1fad1)) * **run:** name Tasks and Runs with four-word identifiers ([#2558](#2558)) ([c82259a](c82259a)) * **run:** prepare a Provider from a Program with coral.workspace.createProvider ([#2351](#2351)) ([e7e56fd](e7e56fd)) * **run:** reshape the Dispatch Fence into one batched check per chunk commit ([#2550](#2550)) ([120c9d3](120c9d3)) * **run:** route approval decisions and cancellation through the Run Owner ([#2577](#2577)) ([77bcbf5](77bcbf5)) * **run:** summarize your recent activity in a Workspace ([#2573](#2573)) ([bf4c75e](bf4c75e)) * **search:** show a Saved Function's result fields in its signature line ([#2522](#2522)) ([41365f6](41365f6)) * **search:** trace each reconcile pass and its steps ([#2456](#2456)) ([0594094](0594094)) * **ui:** add option to create a correctly-configured Slack app during Slack provider setup ([#2585](#2585)) ([8c3a883](8c3a883)) * **ui:** move Add provider to the providers toolbar ([#2591](#2591)) ([e1ee4cb](e1ee4cb)) ### Bug Fixes * **app:** sweep device authorization leases every 15 s ([#2452](#2452)) ([1a4e4ae](1a4e4ae)) * **auth:** drop the unverified client name note from the approval page ([#2578](#2578)) ([ddf5aa4](ddf5aa4)) * **catalog:** derive each Built-in Operation's contract from the types Coral parses ([#2582](#2582)) ([534e636](534e636)) * **catalog:** import OpenAPI Providers whose Operations request different OAuth scopes ([#2401](#2401)) ([3acfe55](3acfe55)) * **catalog:** keep keyword names in Operation Call Paths ([#2506](#2506)) ([b20795b](b20795b)) * **catalog:** never make an Operation unavailable for search material ([#2465](#2465)) ([f83c909](f83c909)) * **catalog:** stop rejecting createProvider request headers by name ([#2589](#2589)) ([39e54b9](39e54b9)) * **provider:** ask for an OAuth client ID when Coral cannot register one ([#2580](#2580)) ([baefe9e](baefe9e)) * **provider:** bind each Setup to its starter and hide Coral from Members ([#2480](#2480)) ([6011a64](6011a64)) * **reef:** align the catalog table with the first rail entry ([#2484](#2484)) ([fb59758](fb59758)) * **reef:** calm the Activity badge and keep it while the stream reconnects ([#2468](#2468)) ([1b66639](1b66639)) * **reef:** frame the providers table again and lower the top bar ([#2472](#2472)) ([87e41ee](87e41ee)) * **reef:** pin third-party recipe OpenAPI documents to a commit ([#2510](#2510)) ([b4e9280](b4e9280)) * **reef:** replace loose help text with info tips and banners ([#2461](#2461)) ([695500a](695500a)) * **reef:** round the page's corners beside the sidebar ([#2503](#2503)) ([a1fef64](a1fef64)) * **reef:** shorten OAuth scope chips that share a URL prefix ([#2455](#2455)) ([5ae67ec](5ae67ec)) * **reef:** suggest a provider's namespace from its document name, not its host ([#2565](#2565)) ([8d77893](8d77893)) * **run:** name every argument to correct in an invalid_input failure ([#2354](#2354)) ([07bd727](07bd727)) * **run:** reject a credential beside createProvider's bearer method and report unreachable sources as upstream_incomplete ([#2542](#2542)) ([590eab7](590eab7)) * **run:** report an MCP JSON-RPC rejection as invalid_input or upstream_rejected ([#2402](#2402)) ([749770b](749770b)) * **search:** load each Generation's schema graph once per search ([#2448](#2448)) ([445d945](445d945)) * **search:** retry a failed Saved Function only after one interval ([#2460](#2460)) ([a61ab3a](a61ab3a)) * **search:** return no hits for a query without a letter or digit ([#2561](#2561)) ([bb0a4f0](bb0a4f0)) * **search:** start the write limit at the lock and build rows before the write ([#2575](#2575)) ([06ad55d](06ad55d)) * **search:** stop a self-referential Promise result from overflowing the stack ([#2543](#2543)) ([1d4f257](1d4f257)) * **search:** stop retrying an index write that fails the same way every time ([#2548](#2548)) ([e3b6d15](e3b6d15)) ### Performance Improvements * **catalog:** dedup credential destinations once per build, not per Operation ([#2555](#2555)) ([0afbcf5](0afbcf5)) * **catalog:** project each named TypeScript type once per Provider ([#2443](#2443)) ([153c273](153c273)) * **search:** drop schema text from the phrase test ([#2559](#2559)) ([cfdbafa](cfdbafa)) * **search:** index each word of schema text once ([#2547](#2547)) ([d1123fb](d1123fb)) * **search:** prepare search entries in the indexer after commit ([#2467](#2467)) ([1ab6765](1ab6765)) * **search:** recount only Workspaces whose rows changed ([#2457](#2457)) ([777cfb3](777cfb3)) * **search:** skip unchanged rows when an index write runs again ([#2459](#2459)) ([43b5188](43b5188)) * **search:** write only the statistics rows that changed ([#2458](#2458)) ([8e2832c](8e2832c)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: coral-release-bot[bot] <269256696+coral-release-bot[bot]@users.noreply.github.com> Co-authored-by: release-please[bot] <release-please[bot]@users.noreply.github.com>
AlbertQM
added a commit
that referenced
this pull request
Oct 22, 2026
## Summary
```diff
<Table.Container layout="fixed"> (apps/reef/app/wax/components/table/container.tsx)
- maxHeight?: number # pixels, heading included
+ maxRows?: number # rows beneath the heading; the rest scroll there
+ # with maxRows, groupHeadings takes only 'plain'
--wax-table-rows-max-height
- maxHeight - HEADING_HEIGHT_PX[density]
+ maxRows * CELL_HEIGHT_PX[density]
```
A caller now names how many rows show, not how many pixels they take, so
a cap follows the density's row height. `CodeBlock` already caps by
`maxLines` in the same way. A prominent group heading is 8px taller than
a row and would cut the last row, so the props reject it with `maxRows`.
```diff
<PermissionsTable> (apps/reef/app/views/accounts/permissions-table.tsx)
- maxHeight={MAX_HEIGHT} # 360: "about ten compact rows"
+ maxRows={10}
```
## Evidence
- **Before:** no test covered the row cap. The permissions table showed
ten rows and a quarter of the eleventh (360 = 32 + 10.25 × 32).
**After:** story `ScrollingRowsInsideTable` (`maxRows={5}`) checks the
cap:
```text
row_4 bottom == rows' scroll port bottom
row_5 top >= rows' scroll port bottom
```
It fails when the cap is 8px taller than five rows.
- `container.test.tsx`: `maxRows` of `0`, `-1`, `1.5`, `Infinity` and
`NaN` throw a `RangeError`; `3` renders. The five rejections fail
without the check.
- Reef: `check`, `typecheck`, `npm test` (2070 unit + 850 story) and
`build` pass. `test:server` has 15 pass and 1 fail in
`scripts/bundle-server.test.mjs`, as #2552 reports.
## Merge Danger
**Door:** two-way
A Wax prop rename. No API, schema or stored state changes.
**Blast Radius:** permissions-table
The permissions list is 8px shorter: it no longer shows part of the
eleventh row. Chromatic shows this change.
AlbertQM
added a commit
that referenced
this pull request
Oct 22, 2026
…2586) ## Summary ```diff <AgentActivityPage> (apps/reef/app/views/management/agent-activity-page.tsx) - variant="split" - header: <AgentQuickStart> + <AgentProviders> (card) - body: {activity} + header (both views): <ArchivedBanner> when the workspace is archived + ?view=activity | readsActivity(query) → variant="split", breadcrumb "Activity", "Back to agent" + {activity} # the complete list, unchanged + otherwise → variant="wide" + <AgentQuickStart> # idle agents only + grid # one column at breakpoints.mobile (640px) + <AgentProviders> # table card, maxRows={3}; hidden with no providers + <section "Recent activity"> # as tall as its records + <LiveActivity more={{ to: "?view=activity", label: "View all activity", roots: 3 }}> ``` `readsActivity` (`app/views/activity/navigation.ts`) is true when the URL selects a record or positions the list: `record`, `tree`, `expand`, `anchor`, paging and branch keys. Only the complete list can show those, so deep links like `agent?expand=<task>` keep working. A record opened from Recent activity also stays on the complete list after you close it. Neither card has a fixed pixel height. Recent activity lists at most three records, and the grid row takes the taller card. ## Evidence - **Before:** the agent page shows the complete Activity beside a setup column, and has no glimpse. Story `AgentActivityAfterRecord` (`agent?anchor=x&tree=1`) fails when the page checks only `view` and `record`. Story `ArchivedAgentFullActivity` fails when the complete Activity drops the header. CI failed `activity/history` (`agent?expand=<task>` showed the dashboard) and `activity/keyboard` (the keyboard reader moved to `?view=activity`). **After:** both stories pass. New Reel scenario `main/agents/dashboard.test.ts` passes on main-sqlite: ```text run 4 agent tasks → agent page lists goals 4, 3, 2; not 1 run goal 5 → appears live; goal 2 drops out View all activity → ?view=activity lists goal 1 → Back to agent → dashboard open goal 5 → ?record=… → Close details → still the complete list ``` - Reef: `check`, `typecheck`, `npm test` (2071 unit + 855 story) and `build` pass. `test:server` has 15 pass and 1 fail in `scripts/bundle-server.test.mjs`, as #2552 reports. - `navigation.test.ts` table test for `readsActivity`. - `container.test.tsx` restores its `console.error` spy after each case, a follow-up to #2601. - Reel main-sqlite on this stack: `agents/`, `activity/keyboard`, `activity/history` and `accounts/` pass (13 files, 21 tests). The full suite runs in CI. ## Merge Danger **Door:** two-way Reef layout and query handling only. No API, schema or stored state changes. **Blast Radius:** agent-page Links to an agent with a record or list position (Run status pages, Activity rows) now open the complete-list view with a breadcrumb "Activity". The dashboard drops to one column at 640px.
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.
Summary
The providers rail becomes a set of tabs. The table shows one provider, or every provider under All providers. This reverses the single scrolling table from v1 (#2321).
Retired with the old rail:
usePinnedProviderAddress,exactFilter(and itsAGENTS.mdrule), and WaxTable.VirtualTail/tailRoom.Evidence
workspace-providers-page.dom.test.tsxasserted no tabs, and that the rail filter and Show only narrowed the table. Reelcatalog/navigationasserted that scrolling rewrote the URL and that a rail click scrolled a short last provider under the head.After:
each rail entry is a tab, and all providers lists every one. The test coversaria-current, the URL, selection that survives a change of tab, and the rail filter narrowing the rail only.Tree Operation Selected(arrival opens the operation's provider tab). The undeclared-hints check moved toTree Operation Without Description.providers/catalog/navigation: a tab shows only its provider, selection survives a change of tab, All providers is the bare address, and a new tab opens at its top.providers/catalog/selection: the provider tab replaces the rail-filter workaround.npm run check,typecheck,npm test(657 pass), andbuild.test:serverhas 15 pass and 1 fail, inscripts/bundle-server.test.mjs, which this PR does not touch. The Reelproviders/folder ran on main-sqlite; results are posted in a comment below.Merge Danger
Door: two-way
Only UI and tests change. No data, API, or URL shape changes. Old provider links still open that provider.
Blast Radius: providers-page
Shared links to a provider now open only that provider's tab, not the whole list scrolled to it. Wax consumers lose
Table.VirtualTail; nothing else used it.