Commit Graph
641 Commits
Author SHA1 Message Date
Ehab Younes 6b297912a5 feat(site): add AI spend to user dropdown (#26698)
Adds the current user's AI spend progress to the top navbar avatar
dropdown when /api/v2/users/me/ai/spend reports a configured spend
limit. The shared dropdown content accepts an optional profileExtra
slot so the Agents sidebar can opt in later without changing the
default sidebar UI.

Introduces a temporary site API type and a React Query helper for
AIGOV-473 that refetches each time the dropdown opens, plus shared
budget progress helpers used by both the new dropdown bar and the
existing Agents usage indicator. The shared AIBudgetUsage component
moves to site/src/components so the dropdown and group budget UI
format spend identically, including the unlimited case. The avatar
border polls the spend endpoint and is colored by severity while the
dropdown is closed.

Closes AIGOV-473
2026-06-30 19:59:13 +03:00
Mathias Fredriksson 2fd5ae4323 fix: stop Agents dead-ending on unsupported providers (#26841)
Configuring only a GitHub Copilot provider left the Agents page stuck on
"set up a provider then add a model", even with a provider and models
configured. The catalog dropped any provider type that NormalizeProvider
did not recognize, so a Copilot-only deployment looked identical to an
empty one and never unlocked the page.

The Agents harness cannot use Copilot: it needs a per-request token only
an official Copilot client can mint, and the harness is not one. Instead
of dropping such providers, the catalog now reports them as unsupported
so the UI can explain the dead end and point elsewhere, rather than ask
for setup that already happened. The providers stay usable through the
AI Gateway proxy.

Support is derived from the provider type, not stored, so there is no
migration. codersdk.IsAgentsUnsupportedProviderType is the single source
of truth, consulted by the chatd catalog and, through the generated
AgentsUnsupportedProviderTypes list, the frontend.

The diff also carries unrelated modernization of nearby db2sdk and
chatprovider helpers (slices.SortFunc, strings.Cut, range-over-int).

Closes CODAGT-627
Refs CODAGT-256
Refs CODAGT-682
2026-06-30 18:49:50 +03:00
McKayla はな a78982c238 test: convert chromatic sentinels to pixel equivalents (#26778) 2026-06-29 08:57:57 -06:00
TJ 5f42bbcdbf feat(site/src): nest agent pages under a Coder Agents subsection in AI nav (#26667)
Groups the agent-related AI settings pages under a new **Coder Agents**
parent in the sidebar, with a continuous left rule connecting the
children and an active-segment indicator that lights up the rule where
the current sub-item sits.

The new nav order:

- AI Governance
- AI Gateway keys
- Providers
- Coder Agents
  - Models
  - MCP servers
  - Templates
  - Spend
  - Instructions
  - Lifecycle

All target pages already exist on main (Danielle's recent migrations of
Models, MCP servers, Templates, Instructions, Lifecycle, Spend, and
Coder Agents into AI Settings). This PR only changes the sidebar visual
structure: the children move into an indented group with a `border-l
border-l-border` rule, and the active child paints a
`border-l-content-primary` segment over that rule via `-ml-px` so the
rule and indicator share a column instead of stacking.

<details>
<summary>Design notes</summary>

Concept 1 from the earlier exploration: always-expanded with indents,
the parent is its own page. Chosen because it adds no expand/collapse
state, no "which child is the default" question, and no animation work;
the parent reuses the existing nav-item, and the children sit in a
wrapper `div` with a left rule. The site bundle ships without Tailwind's
preflight, so the wrapper and sub-item borders are paired with
`border-solid` to actually paint, matching the pattern already in
`Sidebar.tsx`.

</details>

---

_This PR was prepared by Coder Agents on behalf of @tracyjohnsonux._
2026-06-29 13:46:09 +00:00
Danielle Maywood b4a7b25290 feat(site): move Coder Agents settings to AI settings (#26692) 2026-06-29 12:28:36 +00:00
Danielle Maywood cf1c29b651 feat(site): move spend page to AI settings (#26800) 2026-06-29 12:49:38 +01:00
Danielle Maywood 1ae96fcf8a fix!: prevent AI provider name collision with static settings routes (#26688)
Move the providers routes into a dedicated providers sub-tree: `/ai/settings/providers`, `/ai/settings/providers/add`, and `/ai/settings/providers/:providerId`.

The old `/ai/settings/:providerId` and `/ai/settings/add` URLs are
removed without backward-compatibility redirects. Bookmarked or shared
links to these paths now return a 404. Creating a provider with id `models` (although unlikely) made it impossible to edit it due to a conflict with the static models route.
2026-06-25 11:09:58 +01:00
Danielle Maywood 85652554f9 feat: move MCP servers to AI settings (#26642) 2026-06-24 12:30:15 +01:00
Danielle Maywood 3133a8b9c6 feat: move instructions to AI settings (#26624) 2026-06-24 12:29:58 +01:00
Paweł Banaszewski b11cd07d97 chore: move ai gateway keys link up in ai settings (#26654)
Moves 'AI Gateway Keys' link under 'AI Governance' so it doesn't sit between 'Providers' and 'Models'.
Providers remain page loaded by default.
2026-06-24 11:34:54 +02:00
Danielle Maywood 791b4b6413 feat(site): move lifecycle settings to AI settings (#26625) 2026-06-24 10:15:28 +01:00
Danielle Maywood e569e16682 feat(site): move template allowlist to ai settings (#26615) 2026-06-24 10:00:37 +01:00
Susana Ferreira 0807b3272c feat(site): move frontend routes from /aibridge to /ai-gateway with redirects (#26569)
## Description

Moves frontend routes from `/aibridge` to `/ai-gateway` and adds client-side redirects so existing bookmarks and deep links continue to work.

## Changes

- Move React Router paths from `/aibridge` to `/ai-gateway`
- Add `<Navigate>` redirects from `/aibridge`, `/aibridge/sessions`, and `/aibridge/sessions/:sessionId`
- Update `navigate()` calls and `Link` components to use new paths

Closes https://linear.app/coder/issue/AIGOV-233

> Generated with the assistance of Coder Agents (@ssncferreira)
2026-06-24 09:02:36 +01:00
Danielle Maywood ecfff8a7db feat: move model settings page to ai settings 2026-06-23 12:33:28 +01:00
Jake Howell e88f2a3485 feat(site): add bouncy pop animation to inbox notification badge (#26057)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

Replaces the basic `animate-in fade-in zoom-in duration-200` on the
inbox unread badge with a bouncier pop using an overshoot easing.

The badge now pops in from `scale(0)` with `cubic-bezier(0.34, 1.36,
0.64, 1)` over 500ms, giving it an elastic overshoot that makes it feel
alive. Uses `tailwindcss-animate` utilities (`animate-in zoom-in-0
fade-in-0`) with just one arbitrary property for the easing. Conditional
rendering is preserved as before.

Also adds a `BadgeTransition` story with toggle buttons for easy visual
verification.

<img width="150" height="150" alt="preview-notification-animation"
src="https://github.com/user-attachments/assets/70331cd2-c2e2-4fd7-8f9e-edfe876e2bab"
/>
2026-06-23 04:58:59 +00:00
TJ fbf31f2b2d chore(site): swap AI add-on table icons (em-dash + plain check) (#26467)
Updates the icons in the **AI add-on** column for the admin tables on
`/deployment/users` and `/organizations/.../members`.

- Not consuming a seat: `XIcon` → muted em-dash
(`text-content-disabled`).
- Consuming a seat: `CircleCheckIcon` → plain `CheckIcon` from
`lucide-react` (no circle, still `text-content-success`).

Both tables share `site/src/modules/users/AISeatCell.tsx`, so the
single-file change covers `UsersTable.tsx` and
`OrganizationMembersTable.tsx`.

## Screenshot

Users admin table on a local dogfood build of this branch
(`/deployment/users`):

<!-- Drag-and-drop the screenshot here to attach it to the PR. -->

<details>
<summary>Notes</summary>

- The em-dash is rendered via the JSX entity `&mdash;` rather than a
literal `U+2014` character, so it does not trip `make lint/emdash` (see
`AGENTS.md` / `scripts/check_emdash.sh`). The browser still renders an
em-dash.
- Kept the existing `aria-label`s (`Consuming AI seat` / `Not consuming
AI seat`) and added `role="img"` on the em-dash span so screen readers
still announce the state.
- No callers other than `UsersTable.tsx` and
`OrganizationMembersTable.tsx` use `AISeatCell` (verified via search).

</details>

> Opened by Coder Agents on behalf of @tracyjohnsonux.
2026-06-22 14:54:07 -07:00
Andrew Aquino 61fa2ab878 fix(site): set external auth provider polling status individually (#26313)
fixes #22420
ref DEVEX-369
ref DEVEX-269

The bug on `CreateWorkspacePage`, where clicking one external auth
provider login button disabled all providers' login buttons, was caused
by providers all sharing a single polling status (`"idle" | "polling" |
"abandoned"`) in the `useExternalAuth` hook.

## changes

- Instead of setting one status across all providers, the polling status
in `useExternalAuth` is now tracked for each provider in a record whose
keys are the providers' IDs.
- The biggest diff is a new Storybook file
CreateWorkspacePage.stories.tsx which reproduces the bug behavior from
the issue.
- Until now we've only had CreateWorkspacePageView.stories.tsx, which
isn't able to model the user interactions / API responses needed to
verify the bugfix. This file is unchanged.
- Also deletes `CreateWorkspacePage`'s `useExternalAuth` hook in favor
of the global `useExternalAuth` hook (see #26310)

(co-written with Coder Agents)
2026-06-18 11:58:38 -07:00
Andrew Aquino 023a1c992c fix(site): truncate devcontainer name with ellipsis at all screen sizes (#26359)
ref DEVEX-449

## before

In `AgentDevcontainerCard`, the devcontainer's display name truncated
with an ellipsis--but only when the viewport is <768px (parent has
`md:w-full`), which is also when the display name width gets capped at
320px (`max-w-xs`). At larger screen sizes, the display name overlaps
with the rebuild button to the right.


https://github.com/user-attachments/assets/47af30a2-f446-4b5f-bf63-24afb0532b19

## after

Now, the devcontainer display name fills up as much width as possible at
all screen sizes (not just >=768px), and it also gets truncated with an
ellipsis at all screen sizes.


https://github.com/user-attachments/assets/68579438-6fb5-40ea-93cf-c3814dfaac1a

---

(If we have a way to automate resizing screens in Storybook, lmk!)

The trick is to set a `min-width` on the text we want to truncate, see
this CSS Tricks article: https://css-tricks.com/flexbox-truncated-text/

I changed `max-w-xs` to `min-w-[284px]`. In addition to constraining the
display name's width (see "before" above), the `max-width` caused the
rebuild button to wrap to the next line if the screen is too narrow to
show the display name at that width. This behavior on small screens is
preserved. 🙂 However, since the display name's width isn't constrained
anymore, it's written out fully if possible, which causes the rebuild
button to wrap lines on wider screens if the display name is very long.
2026-06-18 09:15:33 -07:00
Atif Ali 0f4a3df2c6 fix: respect automatic_updates policy when building workspace action list (#26362) 2026-06-18 19:57:55 +05:00
Steven Masley be25ba24b0 fix: disable custom roles as possible default org roles (#26461) 2026-06-17 09:15:21 -05:00
Ethan 5ee1946b67 feat: add right panel tabs for workspace apps and ports (#26208)
Adds workspace app and forwarded port tabs to the AgentsPage right panel, so app previews and port views can sit alongside terminals while working in the chat view.

- The new add-tab dropdown lists the agent's apps and a ports submenu: embeddable apps open as iframe tabs, command apps open as renamed terminal tabs running their command, and ports open in a new port preview panel served through the wildcard access URL.
- Tabs persist per chat and are validated against the current workspace state: tabs whose app disappears, stops being embeddable, or whose agent no longer exposes the port forwarding helper are hidden rather than deleted, and reappear if the workspace exposes them again.
- A shared `usePortsData` hook keeps the add-tab control, workspace pill, and existing `PortForwardButton` on the same port queries and refresh cadence.
- ~~App and port tabs are limited to `devel` builds for now; terminal tabs remain generally available. This was done in favour of adding a backend experiment for a frontend-only feature.~~ TODO: I'm just gonna switch to a backend experiment.

Closes CODAGT-346
2026-06-17 13:59:21 +10:00
Asher 744c00f45c fix: handle blank dynamic parameter values consistently (#26122)
There was inconsistency with what the form showed and what actually was
sent to the backend. I opted to make it so that explicitly blank values
are always sent rather than have blank values silently changing to the
default value.
2026-06-16 15:05:27 -08:00
Paweł BanaszewskiandJake Howell e019210f4b feat(site): add AI Gateway keys management page (#25817)
> Vibe-coded using Coder Agents, author with limited frontend knowledge,
manually tested.

Adds an `AI Gateway Keys` page under `Admin settings > AI > AI Gateway
Keys` for key management of keys used by standalone AI Gateway replicas
to authenticate into `coderd`.
The page is shown to users with `viewAIGatewayKeys` permission and a
Premium license with AI Gateway enabled.
Adds Storybook coverage.

---------

Co-authored-by: Jake Howell <jacob@coder.com>
2026-06-15 18:26:58 +02:00
Ethan 7632e73608 refactor(site/src): extract shared workspace-app frame module (#26088)
Extracts the workspace app iframe, wildcard warning, and workspace-app
helper functions out of TaskPage into shared `site/src/modules/apps`
modules. Existing agent and app lookups in the task chat helpers,
download-logs dialog, and workspaces table now route through the shared
`workspaceApps` helpers instead of duplicating resource-flattening
logic. The extracted frame preserves the existing preview-only toolbar
behavior, and its open-in-new-tab link gains `rel="noreferrer"` to
harden against tabnabbing.

Relates to CODAGT-346
2026-06-12 11:51:20 +10:00
Danielle Maywood f865281177 refactor(site): remove CSSProperties assertions (#26234) 2026-06-11 11:21:34 +01:00
Jaayden Halko 5ab25b3ff6 fix(site): add a custom copy/paste menu to the web terminal (#26015)
## Summary

Fixes [CODAGT-415](https://linear.app/codercom/issue/CODAGT-415).

Right-clicking selected text in the web terminal on Windows (and Linux)
showed
the browser's image actions ("Copy image", "Save image as") instead of
copy/paste. The terminal uses xterm.js with the canvas/WebGL renderer,
so the
underlying element is a `<canvas>`, which Chromium and Firefox treat as
an
image. xterm.js tries to retarget the menu by moving a hidden textarea
under
the cursor, but on Windows and Linux the browser's own non-native
context menu
locks onto the canvas before that workaround lands.

## Change

Wrap the terminal in the shared Radix `ContextMenu` so right-click shows
a
custom **Copy** / **Paste** menu instead of the browser default:

- **Copy** reuses the existing copy-on-select clipboard path
(`getSelection()`
  + `copyToClipboard`). It is disabled when there is no selection.
- **Paste** reads the clipboard and uses xterm's `paste()`, which
respects
  bracketed-paste mode.
- The menu is gated to non-macOS (`disabled={isMac()}` on the trigger).
macOS
renders native context menus that already expose working copy/paste
across
  Chrome, Firefox, and Safari, so its default is left untouched.

## Platform scope

| Platform | Behavior |
| --- | --- |
| Windows (Chromium / Firefox) | Custom Copy/Paste menu (fixes the bug)
|
| Linux (Chromium / Firefox) | Custom Copy/Paste menu |
| macOS (Chrome / Firefox / Safari) | Native menu preserved (already
works) |

## Testing

- `TerminalPage.test.tsx`: on non-macOS, right-click suppresses the
native menu
  and shows the Copy/Paste menu; on macOS the native menu is preserved.
- `TerminalPage.stories.tsx`: new `RightClickMenu` story opens the menu
via a
  `play` function for real-browser and visual coverage.
- `tsc`, `biome`, and `make pre-commit` (gen/fmt/lint/build) pass
locally.

<details>
<summary>Decision log</summary>

- The issue was originally reported as Windows-only. Hands-on testing
confirmed
macOS is not affected: Chrome, Firefox, and Safari on macOS all show a
working
copy/paste menu. The difference is the menu implementation: macOS uses
native
  OS context menus (which pick up xterm's repositioned textarea), while
Chromium/Firefox on Windows and Linux draw their own menu that targets
the
  `<canvas>` directly.
- Root cause is the canvas/WebGL renderer plus the unreliability of
xterm's
textarea-repositioning workaround on non-native menus, not the operating
  system itself.
- A custom menu (rather than just `preventDefault`) was chosen so users
keep an
  explicit copy/paste affordance on the affected platforms. A bare
  `preventDefault` removes the menu entirely.
- Scope is gated to non-macOS to avoid regressing the working native
menu on
macOS. Rejected alternatives: suppressing/replacing on all platforms
(regresses
macOS), and Windows-only (misses Linux, which shares the same non-native
menu).

</details>

---

Generated by Coder Agents on behalf of @jaaydenh.
2026-06-11 09:12:15 +01:00
Ethan 2e47d33c2c fix(site/src/modules/resources): restore log auto-expand on script failure (#26237)
#26124 introduced a regression on `main`: `AgentRow ›
NonStartupScriptError` fails because the refactor replaced
`hasAgentIssues` (which covered both connectivity and script issues)
with `hasConnectivityIssues` only in the `showLogs` condition. For a
`ready` agent with a failed script but no connectivity issues,
`showLogs` becomes false, logs never load, and the failed script tab
never renders. The PR's own behavior table said logs should still
auto-open in this case — it was an implementation oversight, not an
intentional change.

Fix by including `hasScriptIssues` in the `showLogs` condition alongside
`hasConnectivityIssues`, restoring the auto-expand behavior from #25442
without touching connectivity badge styling.

> **Note:** This reached `main` undetected because `test-js` in CI only
runs `--project=unit`; the Storybook interaction tests
(`--project=storybook`) that caught this are not a required check. When
Chromatic is switched off, `--project=storybook` should be added to the
required gate.

Refs #26124, #25442
2026-06-11 05:45:59 +00:00
Atif Ali 9e1c502ece fix(site): delink agent health from script failures (#26124) 2026-06-11 09:30:15 +05:00
Susana Ferreira 777ac44226 refactor: rename "AI Bridge" to "AI Gateway" in the UI (#26161)
Renames all user-visible "AI Bridge" strings to "AI Gateway" in the
browser UI as part of the AI Bridge to AI Gateway rebrand (AIGOV-233).

Changes:
- Page titles and headings ("AI Bridge Logs" to "AI Gateway Logs",
`pageTitle` calls)
- Help popover title, description, and doc link
- Setup alert title, description, and doc link
- Back-link tooltip on session threads page
- AI add-on help popover text
- License entitlement warning shown in the dashboard banner

Doc links updated from `/ai-coder/ai-bridge` to `/ai-coder/ai-gateway`
(directory already exists).

This PR intentionally does not rename internal identifiers,
file/directory names, API endpoints, routes, CLI help, deployment config
options, or generated types. Those will be tracked separately.

Related to: https://linear.app/codercom/issue/AIGOV-233

> Generated by Coder Agents on behalf of @ssncferreira
2026-06-09 15:11:27 +01:00
Ethan db00007605 feat: support multiple terminal tabs on the agents right panel (#26089)
- Adds a dynamic terminal tab model to the Coder Agents right panel so
users can open, switch between, and close multiple Web Terminal sessions
for the same agent.
- Each terminal tab generates its own UUID reconnect token and is
persisted per agent in local storage, so tabs and their PTY sessions
survive reloads.
- New terminal tabs are auto-labelled (`Terminal 2`, `Terminal 3`, ...),
filling the lowest free number.
- The built-in Terminal tab is now closeable; closing it hides it and
persists that choice per agent, and it can be restored from the add-tab
control.
- Only the active terminal (and a tab that is mid-activation) mounts the
expensive xterm/WebSocket/PTY resources; a freshly hidden terminal stays
warm for 30s to keep quick tab toggles instant, then detaches to bound
resource usage instead of capping the tab count.
- Inactive terminals stay laid out but hidden, and a newly opened
terminal is not activated until it reports ready (or 100ms), avoiding
the narrow refit and blank-frame flicker when switching between terminal
canvases.
- The right-panel tab bar scrolls horizontally with chevron controls
when tabs overflow, keeping everything on a single row.
- Per-agent right-panel tab and hidden-terminal state is cleared from
local storage when a chat is archived or deleted.
- Adds unit tests for the tab utilities, persistence helpers, and the
warm/detach lifecycle hook, plus Storybook play-function coverage for
the tab and terminal components.

Relates to CODAGT-346
2026-06-10 00:08:01 +10:00
Steven Masley 69f9b0e535 feat(site): show org default roles in member role editor (#26107)
Surfaces the org's `default_org_member_roles` inside the org members role editor. These roles are implied, not physically assigned to any member. Just like the `member` role.
2026-06-05 20:51:20 -05:00
Steven Masley 938c2080f3 feat: configurable default org member roles (#25994)
Refs #25936. 
Adds a configurable per-org default member role set. Unioned into each member's effective roles at read time.

<sub>with Coder Agents on behalf of @Emyrk.</sub>
2026-06-05 14:33:13 -05:00
Andrew Aquino 2ef468ef76 test: reset pointer-events before each Storybook story (#26081)
fixes DEVEX-402

Alternative to #26077, which aimed to address this flake in
UsersPage.stories.tsx only:

>Unable to perform pointer interaction as the element has
`pointer-events: none`

In the original PR I was going to "fix" the flake by adding
`pointerEventsCheck: Never` like we have in 2 other tests. However,
resetting `pointer-events` during `beforeEach` in our global Vitest
setup removes the need for that `pointerEventsCheck` workaround. 🙂

tl;dr: Each of these 3 tests were failing because of an immediately
preceding test which opens a Radix Dialog, setting `pointer-events:
none` on the body element.

Co-written with Coder Agents. Relevant chat responses:

>**The actual root cause is story isolation.** The previous story
(`UpdateUserRoleSuccess`) opens a Radix Dialog, which triggers Radix's
`DismissableLayer` to set `document.body.style.pointerEvents = "none"`.
When that story completes, Storybook unmounts the React tree, but the
cleanup of `body.style.pointerEvents` is tied to a `useEffect` cleanup
in `DismissableLayer`. If Storybook begins the next story's play
function before the browser has fully flushed the previous unmount
cycle, `document.body.style.pointerEvents` is still `"none"`. The "Open
menu" button, which is a plain table button with no Radix modal layer
above it providing `pointer-events: auto`, inherits `"none"` from body,
and the first click fails.
>
>**Why it's flaky:** The Storybook Vitest plugin
(`@storybook/addon-vitest`) runs stories sequentially in the same
browser page. When `UpdateUserRoleSuccess` finishes, React unmounts the
tree, and `DismissableLayer`'s `useEffect` cleanup should restore
`body.pointerEvents`. But there's a race between unmount cleanup
completing and the next story's play function starting. Sometimes
cleanup wins (test passes), sometimes the play function wins (test
fails).
>
>**[#26077]'s `pointerEventsCheck: Never`** works but is a workaround.
It doesn't address the leaked state, and `UpdateUserRoleSuccess` itself
could be flaky too (if whatever story precedes it leaves the same stale
state). The other stories in the same file (Suspend, Delete, Activate,
ResetPassword) all open Radix Dialogs too, so any of them could leak
this state to the next story.
2026-06-05 12:05:28 -07:00
6b556ea873 fix(site): default agent logs tab to failed script, else All Logs (#25442)
> 🤖 This PR was modified by Coder Agents on behalf of Jake Howell.

The agent logs tab was snapping to **Startup Script** whenever
`getAgentHealthIssues` returned _any_ issue, including non-script issues
like:

- agent `status` of `connecting`, `timeout`, or `disconnected`
- lifecycle `shutting_down`, `shutdown_error`, or `shutdown_timeout`
- any script with status `timed_out`, `exit_failure`, or
`pipes_left_open`

So users routinely landed on a filtered Startup Script view (even
mid-connect) and had to click back to **All Logs** to see the full
picture.

### Change

- Default to **All Logs** on mount.
- Once logs stream in, if any script has actually failed _and_ its
source has rendered log entries, auto-select that script's tab. The
visibility check is the same one the tab list uses, so we never point
`selectedLogTab` at a tab that isn't rendered.
- A ref ensures the auto-select fires at most once and never overrides a
manual tab change by the user.
- The failure predicate (`exit_code` truthy or `status` set and not
`"ok"`) is extracted into an `isScriptFailed` helper so the auto-select
and the per-tab error indicator stay aligned.

### Behavior matrix

| Agent state | Before | After |
| ------------------------------------------------------ |
--------------- | ------------------------------ |
| Healthy, scripts running normally | All Logs | All Logs |
| `connecting` / `timeout` / `disconnected` | Startup Script | All Logs
|
| `shutting_down` / `shutdown_error` | Startup Script | All Logs |
| Startup Script failed, has logs | Startup Script | Startup Script |
| Non-startup script failed, has logs (e.g. install) | Startup Script |
The failed script's tab |
| Failed script with **no logs**, other sources have logs| Startup
Script (broken: tab not rendered) | All Logs |

### Test coverage

Four `play` functions on `AgentRow.stories.tsx`, each pinned to a
hardcoded tab name so a predicate regression can't silently pass:

- **`StartError`** — failed script with logs is auto-selected.
- **`StartErrorWithoutFailedSourceLogs`** — failed script with no logs
keeps All Logs active; we never point at an invisible tab.
- **`ConnectingWithStartupLogs`** — connecting agent with no script
failure stays on All Logs (locks in the bug fix for connection-only
issues).
- **`NonStartupScriptError`** — only a non-startup script fails (Startup
Script is OK); the auto-select tracks the failure, not position or
display name.

Each play function was verified to actually run by deliberately failing
the assertion once and confirming the test errored.

<details>
<summary>Decision log</summary>

The shape evolved during review:

1. First pass: collapse to `useState("all")`. Reviewer noted this lost
the auto-jump for legitimate failures.
2. Second pass: `useState(failedSourceId ?? "all")`. Codex flagged that
`failedSourceId` could point to a tab with no rendered entries, breaking
the Logs panel.
3. Final pass (this PR): `useState("all")` + `useEffect` + ref.
Auto-jump only fires once, only when the failed source has rendered
logs, and never overrides a manual selection.

Deferred from coder-agents-review feedback:
- **DEREM-5**: `agent.log_sources.find(...)` can disagree with the tab
bar's sort order when multiple non-startup scripts fail concurrently.
Low probability, one click to recover. Worth a follow-up if it becomes a
real complaint.

</details>

### Verification

- `pnpm check` (biome) — clean
- `pnpm lint:types` (tsc) — clean
- `pnpm vitest run --project "storybook (chromium)"
src/modules/resources/AgentRow` — 28/28 passed

---------

Co-authored-by: Atif Ali <atif@coder.com>
Co-authored-by: Jeremy Ruppel <jeremy.ruppel@gmail.com>
2026-06-04 19:13:54 +05:00
TJ d1d4b89bd7 fix(site): scope menu item icon sizing to direct children (#26040)
The descendant selector `[&_img]:size-icon-sm` in `menuItemClass` was
matching the `<img>` nested inside `<Avatar>` on the User settings row
of the mobile menu, pinning the avatar image to `1.125rem` instead of
letting it fill its Avatar container. The same descendant rule also
applied to nested SVGs.

Switch both rules to direct-child selectors (`[&>svg]`, `[&>img]`),
matching the symmetric `shrink-0` rules already next to them and the
same pattern used in `Button.tsx`. Menu items that contain nested
`<img>`s already set their own sizes explicitly (`w-4 h-4` in
`ProxySettingsSub`, `!size-3.5` in `WorkspacePill`), so this only stops
overriding components like `Avatar` that manage their own internal
sizing.

Also removes the now-dead `[&_img]:w-full [&_img]:h-full` workaround in
`UserDropdownContent.tsx` that fought the same bug per-item; that menu
item no longer renders an `<img>`, and the root fix makes the workaround
unnecessary anyway.

Refs
[CODAGT-552](https://linear.app/codercom/issue/CODAGT-552/mobile-menu-user-avatar-image-is-undersized-inside-its-container)

<details>
<summary>Investigation notes</summary>

**Repro (before):** mobile viewport, user has an image avatar set, open
hamburger menu, observe the avatar in the User settings row is smaller
than its bordered square.

**Root cause:** `site/src/components/DropdownMenu/menuClasses.ts` set
`[&_img]:size-icon-sm` using a Tailwind descendant selector (`_`). That
matches every `<img>` *inside* a menu item, including the one nested
inside `<AvatarPrimitive.Root>`. The Avatar's inner image is supposed to
be `aspect-square size-full object-contain` and inherit its size from
the Avatar root (`--avatar-default` ≈ 24px by default), but the
descendant rule overrides that and pins it to 1.125rem.

**Prior workaround:** `UserDropdownContent.tsx` previously added
`[&_img]:w-full [&_img]:h-full` per-item to fight the same bug on
desktop. That menu item no longer renders an `<img>`, so the override
was already dead code; removed here for hygiene.

**Safety check on the wider change:** every other menu item that
contains a nested `<img>` already sets its own sizes explicitly:
- `ProxySettingsSub` (`MobileMenu.tsx`): `<ExternalImage className="w-4
h-4" />`
- `WorkspacePill.tsx`: `[&_svg]:!size-3.5 [&_img]:!size-3.5` on the menu
content

Direct-child icons (`ChevronRightIcon`, `CircleHelpIcon`, `XIcon`,
lucide icons in `UserDropdownContent.tsx`) remain direct children of the
menu item, so `[&>svg]:size-icon-sm` keeps sizing them as before.

</details>

---

_Authored by Coder Agent on behalf of @tracyjohnsonux._
2026-06-04 00:22:00 -07:00
Andrew Aquino 887ea21237 feat: show Spinner before agent logs are rendered (#25820)
related to DEVEX-313


https://github.com/user-attachments/assets/5fb074bd-7ee7-4f11-9c0a-30567cd71abc
2026-06-02 11:49:10 -07:00
Ethan 49c2142d2d fix: allow unlinking chat workspaces (#25833)
This allows a Coder Agents chat to detach from its linked workspace
without deleting or changing the workspace, so a different workspace can
be linked later. It adds detach controls wherever the linked workspace
appears, including the workspace pill menu, fallback workspace badges,
and the workspace picker. The workspace selection state now updates
consistently across desktop and mobile.

Running workspace:
<img width="453" height="296" alt="image"
src="https://github.com/user-attachments/assets/ac5197a7-f0f4-4123-bbea-d3ddaca7a3e4"
/>

Stopped workspace:
<img width="389" height="203" alt="image"
src="https://github.com/user-attachments/assets/f5a8a90c-4bb0-405a-ade3-791146687b2d"
/>


Closes CODAGT-510
2026-06-02 14:40:07 +10:00
Atif Ali 6f5220202d fix(site/src/modules/resources): clarify agent log download button label (#25641) 2026-05-31 10:03:34 +05:00
Jon Ayers c248dfb437 fix: escape agent log HTML (#25808) 2026-05-28 14:43:07 -05:00
Danielle Maywood d1e27889eb fix(site): improve chat sharing mobile layout (#25687) 2026-05-27 15:03:29 +01:00
blinkagent[bot]andblink-so[bot] dd741bd188 fix(site): only highlight Providers item on exact match in AI settings sidebar (#25700)
## Problem

When visiting `/ai/settings/governance`, both **AI Governance** and
**Providers** items in the AI settings subnav appear highlighted as
active.

## Cause

`SettingsSidebarNavItem` is built on react-router's `<NavLink>`, which
by default treats a link as active when the current URL **starts with**
the link's `to` path. Since `/ai/settings/governance` starts with
`/ai/settings`, the Providers item is also marked active.

## Fix

Pass `end` on the Providers nav item so it only matches when the path is
exactly `/ai/settings` (the index route). The `SettingsSidebarNavItem`
component already supports this prop for exactly this case.

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-05-26 19:23:13 +00:00
Jake Howell d80b484487 feat(site): promote AI settings to a top-level section (#25582)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

Linear: [DEVEX-355](https://linear.app/coder/issue/DEVEX-355)

Fifth and final PR in a 5-PR stack splitting #25328. Surfaces the AI
settings section in the dashboard chrome and moves the existing AI
Governance page out of `/deployment`.

- `Navbar` / `NavbarView` / `DeploymentDropdown` gain a
`canViewAISettings` prop sourced from the `viewAnyAIProvider` permission
added in PR 2. The deployment dropdown gets a new AI entry that links to
`/ai/settings`.
- `DeploymentSidebarView` drops the AI-related entries that now live
under `/ai/settings`.
- `AISettingsSidebarView` expands to include AI Governance and a
cross-section link to Manage Coder Agents.
- `router.tsx` removes the `/deployment/ai-governance` route and mounts
the matching `/ai/settings/governance` child route under the new AI
settings layout.
- `ChatsSidebar` settings panel repoints the Providers link from
`/deployment/ai-providers` to `/ai/settings`.

<details>
<summary>Stack</summary>

1. #25579 jakehwll/DEVEX-355/01-primitives, primitives
2. #25580 jakehwll/DEVEX-355/02-api, API client and query layer
3. #25581 jakehwll/DEVEX-355/03-components, provider form components
4. #25583 jakehwll/DEVEX-355/04-pages, pages and routes
5. **jakehwll/DEVEX-355/05-section, section reshuffle (this PR)**

Replaces #25328 once the stack lands.
</details>
2026-05-26 16:50:36 +00:00
Jake Howell 0a7ac7c986 feat(site): add AI settings providers pages and routes (#25583)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

Linear: [DEVEX-355](https://linear.app/coder/issue/DEVEX-355)

Fourth PR in a 5-PR stack splitting #25328. Wires the new `/ai/settings`
provider management UI.

- `AISettingsLayout` hosts the section under `/ai/settings` with a
sidebar outlet.
- `AISettingsSidebar(View)` shows a single "Providers" nav entry. The
remaining sidebar entries arrive with the broader AI settings section
reshuffle in the next PR.
- `ProvidersPage` lists configured AI providers via the queries added in
PR 2.
- `AddProviderPage` walks through provider-type selection and form
submission, with type-specific credential fields.
- `UpdateProviderPage` edits an existing provider with the same form
components.
- Storybook stories cover each view's loading, empty, populated, error,
and form states using the mock providers from `testHelpers/entities.ts`.
- `router.tsx` mounts the new `/ai/settings` layout with index, `add`,
and `:providerId` child routes. The `governance` child route lands
together with the dashboard navigation changes in the next PR.

Removes the now-unused knip ignore entries for
`src/api/queries/aiProviders.ts` and
`src/pages/AISettingsPage/ProvidersPage/components/addableProviderTypes.ts`,
and drops the matching `@lintignore` tags on `getProviderIcon` and
`MockAIProviders` since the pages and page stories now consume them.

<details>
<summary>Stack</summary>

1. #25579 jakehwll/DEVEX-355/01-primitives, primitives
2. #25580 jakehwll/DEVEX-355/02-api, API client and query layer
3. #25581 jakehwll/DEVEX-355/03-components, provider form components
4. **jakehwll/DEVEX-355/04-pages, pages and routes (this PR)**
5. jakehwll/DEVEX-355/05-section, section reshuffle

Replaces #25328 once the stack lands.
</details>
2026-05-26 16:38:34 +00:00
Jake Howell 5d39c833f8 feat(site): add AI provider API client and query layer (#25580)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

Linear: [DEVEX-355](https://linear.app/coder/issue/DEVEX-355)

Second PR in a 5-PR stack splitting #25328. Adds the frontend layer that
talks to the existing `/api/v2/ai/providers` endpoints already shipped
on `main`:

- API client: `getAIProviders`, `getAIProvider`, `createAIProvider`,
`updateAIProvider`, `deleteAIProvider`.
- React Query wrappers in `queries/aiProviders.ts` with a shared key
helper and matching cache invalidations.
- Mock fixtures for OpenAI, Anthropic, and Bedrock providers in
`testHelpers/entities.ts` for stories and unit tests.
- `viewAnyAIProvider` registered in `permissions.json` so the existing
permissions hook can read it.
- `viewAnyAIProvider` added to `canViewDeploymentSettings` so admins who
can only manage providers still see the deployment dropdown.

The `aiProviders` query module and the per-provider mocks are
temporarily added to the `knip` ignore list / annotated with
`@lintignore`; the next PRs in the stack consume them and remove the
exclusions.

<details>
<summary>Stack</summary>

1. #25579 jakehwll/DEVEX-355/01-primitives, primitives
2. **jakehwll/DEVEX-355/02-api, API client and query layer (this PR)**
3. jakehwll/DEVEX-355/03-components, provider form components
4. jakehwll/DEVEX-355/04-pages, pages and routes
5. jakehwll/DEVEX-355/05-section, section reshuffle

Replaces #25328 once the stack lands.
</details>
2026-05-26 16:13:11 +00:00
Atif Ali 2ad2f7869d chore(site): rename AI Bridge Sessions dropdown to AI Sessions (#25656)
Renames the admin settings dropdown label from "AI Bridge Sessions" to
"AI Sessions". The link target (`/aibridge/sessions`) is unchanged.
2026-05-25 16:23:38 +00:00
Jake Howell 4c91069479 fix: append asChild to <AgentApps /> (#25547)
This pull-request resolves a stupid issue wherein the `<DropdownItem />`
would wrap into an `<AppLink />` causing two hit targets. This now is a
single one and inline with the Figma Coder Kit after the parent merges
onto the child.

| Old | New |
| --- | --- |
| <img width="400" alt="preview-broken-button"
src="https://github.com/user-attachments/assets/b74018a7-9279-4464-b71b-a16901e844c9"
/> | <img width="308" height="141" alt="image"
src="https://github.com/user-attachments/assets/8b4a1371-e1bb-4341-9a6a-033a7b48c31d"
/> |
2026-05-22 00:21:26 +10:00
Jake Howell 1fdb8ed9a0 fix: wrap latestVersion?.message with <div /> (#25549)
This pull-request wraps the `latestVersion?.message` in a `<div />` so
that our content is affected by the `flex flex-col` class from the
parent.

| Old | New |
| --- | --- |
| <img width="441" height="363" alt="PREVIEW_1"
src="https://github.com/user-attachments/assets/0693136a-cfcc-4f17-a94d-35c14943c3bd"
/> | <img width="441" height="295" alt="PREVIEW_1_NEW"
src="https://github.com/user-attachments/assets/ce6c1126-6153-4d7f-a4b8-f01a5a98e270"
/> |
| <img width="441" height="396" alt="PREVIEW_2"
src="https://github.com/user-attachments/assets/b26e81b4-09fb-4317-9d25-3ca8b5989c54"
/> | <img width="441" height="294" alt="PREVIEW_2_NEW"
src="https://github.com/user-attachments/assets/241afe85-c278-4593-a985-bcc2400ac52f"
/> |
2026-05-22 00:20:41 +10:00
Rowan Smith 57ed244de1 chore: update cli install link to use local deployment URL instead of coder.com (#25548)
Updates the connect via SSH menu shown in workspaces to redirect to
`/install` on the local deployment instead of
`https://coder.com/docs/<version>/install`. This ensures consistency
with the user account dropdown menu which also references the local
deployment.

End goal is to ensure the user running install script receives the same
CLI version as is running on the Coder deployment.
2026-05-21 15:12:06 +10:00
Atif AliandMichael Suchacz 7ffeac711c fix: correct web terminal glyph rendering and tmux display (#25059)
The web terminal was rendering Claude Code and Codex incorrectly because
xterm's custom glyph renderer draws block and quadrant characters with
its own geometry. The reconnecting PTY screen backend also exposed
`screen.xterm-256color` to the user's shell, which made tmux rendering
issues harder to reason about.

This PR:

* Disables xterm custom glyph rendering so the selected terminal font
draws block and quadrant glyphs.
* Adds a tiny Powerline-only terminal symbol fallback font so common
prompt separators still render when custom glyphs are disabled.
* Configures the screen backend to keep the inner shell `TERM` aligned
with the browser terminal emulator, including background color erase
behavior.
* Tightens reconnecting PTY tests around prompt synchronization and
`TERM` assertions.

<!-- linear:table-colwidths:200,200 -->
| Before | After |
| -- | -- |
| <img
src="https://uploads.linear.app/e62091d9-44f5-421c-8e5c-df481fc99003/3c45efce-9d7e-43b4-b24f-88d4d23d294a/ba68155e-949e-4961-b0b2-124757cb07bb?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXRoIjoiL2U2MjA5MWQ5LTQ0ZjUtNDIxYy04ZTVjLWRmNDgxZmM5OTAwMy8zYzQ1ZWZjZS05ZDdlLTQzYjQtYjI0Zi04OGQ0ZDIzZDI5NGEvYmE2ODE1NWUtOTQ5ZS00OTYxLWIwYjItMTI0NzU3Y2IwN2JiIiwiaWF0IjoxNzc4MTgxNjUwLCJleHAiOjE4MDk3NTIyMTB9.45f1ZzBpWOF5OCJV0xHfICdpyRQ1UoGMbJjLYPqeAkg
" alt="Before: Claude Code logo rendering is distorted in the web
terminal outside and inside tmux" width="640" /> | <img
src="https://uploads.linear.app/e62091d9-44f5-421c-8e5c-df481fc99003/26b0a109-5e21-4000-b1b5-ddac87c409d4/46a301c2-a815-419a-92d2-c51cecdefe40?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXRoIjoiL2U2MjA5MWQ5LTQ0ZjUtNDIxYy04ZTVjLWRmNDgxZmM5OTAwMy8yNmIwYTEwOS01ZTIxLTQwMDAtYjFiNS1kZGFjODdjNDA5ZDQvNDZhMzAxYzItYTgxNS00MTlhLTkyZDItYzUxY2VjZGVmZTQwIiwiaWF0IjoxNzc4MTgxNjUwLCJleHAiOjE4MDk3NTIyMTB9.SQVwUbtaf2OrpjRJPkRH3uc0nPqad0bNBVvcRyuR6NQ
" alt="After: Claude Code logo renders correctly in the web terminal
outside and inside tmux" width="640" /> |

## Validation

* `go test ./agent -run '^TestAgent_ReconnectingPTY$' -count=1`
* `pnpm --dir site test -- src/theme/constants.test.ts`
* `pnpm --dir site lint:types`
* `pnpm --dir site check`
* `pnpm --dir site build`
* `git commit` pre-commit hook passed
* `git push` pre-push hook ran and printed the repo CI monitoring hint

> Mux worked on this PR on Mike's behalf.

---------

Co-authored-by: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com>
2026-05-20 13:57:50 +02:00
Ethan 4c362499f2 fix(site): keep workspace quota meter live-updated in Agents chat (#25468)
The workspace quota meter in the Agents chat sidebar previously only
refreshed on a full page reload, while the AI cost-usage meter rendered
next to it already polled every 60 seconds.

This change gives the Agents usage indicator the same 60s
workspace-quota polling and refreshes derived workspace caches
immediately when workspace-affecting chat tools complete.
`create_workspace`, `start_workspace`, and `stop_workspace` now
invalidate the workspace quota and `workspaces` query family, so both
the credit numbers and the workspace-count detail stay in sync.

`create_workspace` still invalidates the chat record to resolve
workspace bindings, and archive-and-delete uses the shared workspace
mutation invalidation helper so deleting an agent workspace refreshes
the same derived workspace data.

Closes CODAGT-444


Tested manually and it works perfectly.
2026-05-20 12:30:28 +10:00