Commit Graph
609 Commits
Author SHA1 Message Date
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
Kayla はな 2943bf5f21 fix(site): use ExternalImage for icon URLs (#25315) 2026-05-13 17:52:05 -06:00
Kayla はな 660fa9478f style(site): use shorthand for boolean JSX props (#25096) 2026-05-13 10:56:50 -06:00
Cian Johnston caabb3c4ab fix(site): show Organizations in admin dropdown for single-org OSS deployments (#25175)
Fixes https://linear.app/codercom/issue/CODAGT-350

On OSS or no-license single-org deployments, the Organizations admin
link was hidden because `canViewOrganizationSettings` was gated on
`showOrganizations`, which requires either a multi-org entitlement or >1
org. The page was still reachable via direct URL, but the members view
displayed a raw "Template RBAC is a Premium feature. Contact sales!"
error from the groups API.

Two fixes:

1. Always render the Organizations link inside the `DeploymentDropdown`.
The dropdown itself is only shown to users with admin-level permissions,
so Organizations is effectively gated on having admin access.

2. Remove `groupsByUserIdQuery.error` from the error chain on the
members page. The groups endpoint is gated behind
`templateRBACEnabledMW` on enterprise, returning a 403 on OSS. The
groups data is already optional, so the page renders fine without it.

> Generated by Coder Agents
2026-05-12 12:28:43 +01:00
Kayla はな 638e2220e9 chore: refactor BuildIcon and remove useClassName (#25017) 2026-05-08 14:11:49 -06:00
Jeremy Ruppel a638f099c8 fix(site): show running script count instead of log source count in agent log badge (#25079)
The badge next to the loading spinner in the agent logs section was
showing `agent.log_sources.length` (total log sources registered on the
agent). This is a static count unrelated to what's actively running.

Now it shows the count of startup scripts still in progress: scripts
where `run_on_start` is true and `status` is not yet set. Scripts
without a `status` haven't completed; completed scripts receive `"ok"`,
`"exit_failure"`, `"timed_out"`, or `"pipes_left_open"`. The badge also
hides when zero scripts are running.

> [!NOTE]
> Generated by Coder Agents
2026-05-08 09:37:03 -04:00
Ethan 987d415be3 feat(site): show workspace quota failures in chats (#25020)
Create and start workspace tool cards now recognize `INSUFFICIENT_QUOTA`
results and use the server-provided quota failure title in the build-log
dropdown. The existing warning icon and tooltip remain, while the
assistant response remains the place for the detailed recovery guidance.

Adds Storybook coverage for quota-reached create and start workspace
results.

https://github.com/coder/coder/pull/24956 added the necessary backend
changes.
<img width="897" height="505" alt="image"
src="https://github.com/user-attachments/assets/6cab8798-393d-429f-a3c3-a8ed50402d42"
/>



Closes CODAGT-20
2026-05-08 13:25:53 +10:00
Kayla はな 9fd2cc78fe refactor(site): migrate more styles from emotion to tailwind (#24914) 2026-05-07 11:09:25 -06:00
Jake Howell 8c2b1c7d69 chore: de-emotion style constant (#24835)
This pull-request looks at all (most) of our instances of `const styles
= { ... }` and attempts to smooth them down into the minimum viable
Tailwind equivalent 🙂
2026-05-07 09:21:24 +10:00
Kayla はな 4e1dccaabd refactor: remove ChooseOne component (#24983) 2026-05-06 12:08:51 -06:00
Bartek Gatz 894a1e0f7f feat(site): add Codernauts lunar lander game (#25001) 2026-05-06 17:50:46 +00:00
Jake Howell 859e5d3dda fix: remove last import of @mui/material/SvgIcon (#24916)
This pull-request finds the last place we make use of
`@mui/material/SvgIcon` and removes it 🙂 Therefore, another MUI import
we no longer need.
2026-05-06 11:50:52 +10:00
Kayla はな 21a877df84 feat: update OrganizationMembersPage role editing to match new designs (#24858) 2026-05-05 13:18:01 -06:00
Kayla はな 162acaf8bf feat: update UsersPage role editing to match new designs (#24857) 2026-05-04 11:19:21 -06:00
Asher 453a39be97 feat: show ui for individual failed scripts (#24506)
Previously we only showed an error when the startup script failed.  Now:

- Add a warning icon to each failed script.
- Sort the failed script tabs first.
- Modify agent health messages to pull the errors notices from the new 
  location instead of from the single agent lifecycle enum. This means
  errors are shown for each script and the count is accurate.
2026-05-01 10:54:23 -08:00
Jeremy Ruppel 8709d42fe0 feat(site): add loading <Spinner /> to AgentRow (#24825)
Adds a `<Spinner />` next to the log count during agent startup.

Also, there was some complexity in sizing the spinner because `<Badge
/>` automatically sizes any `svg`s it contains to `size-icon-xs`. In
order to maintain the `svg` sizing inside existing Badges across the
site, this introduces a new `svgSize` prop that defaults to `xs`.
Existing consumers will still get `[&_svg]:size-icon-xs` regardless of
the Badge size, but can now be overridden to `sm` or `lg` (there is no
`md`).

Also also fixes a tiny spacing issue with the warning triangle
🕵️‍♂️

<img width="1203" height="624" alt="Screenshot 2026-04-29 at 3 24 35 PM"
src="https://github.com/user-attachments/assets/e4fc4a3a-e88f-4253-a697-195f8a347230"
/>
2026-05-01 10:57:30 -04:00
Kayla はな 90bee3aaef refactor: reorganize and restyle some oddities (#24855) 2026-04-30 19:09:41 -06:00
Jeremy Ruppel 386d836366 feat(site): remove visible text from copy/download logs buttons (#24852)
The text from the AgentRow copy/download logs buttons were cramping
actual log stream tabs. Design would like to hide this text:

1. The "Copy logs" text is now in a tooltip over the button
2. The "Download logs" text is now screen-reader only


https://github.com/user-attachments/assets/af883cae-67dc-4198-9fde-0ab5ea415360
2026-04-30 16:50:08 -04:00
Ben Potter 8471b19248 feat: improve mobile responsiveness (#24821)
Linear: DEVEX-270

The nav links (Workspaces, Templates, Tasks, Agents) were always
rendered horizontally, overflowing on small viewports and pushing
right-side controls (notifications, user menu, hamburger) off-screen.
The Agents page has no Navbar since it sits outside DashboardLayout,
leaving mobile users with no way to navigate back.

- Hide nav links below `md` breakpoint; they now live in the hamburger
menu alongside the existing admin/user settings sections
- Add Workspaces, Templates, and Agents entries to the mobile menu
dropdown
- Show the Agents sidebar logo header on all viewports (was `hidden
md:block`), giving mobile users a tap target back to `/workspaces`
- Reduce workspace page content padding from `p-8` to `p-4 md:p-8`, with
matching negative-margin fix on `ResourceMetadata`

## Demo (390px / iPhone viewport, 1.75x speed)


![mobile-demo](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/mobile-demo.gif)

## Screenshots (390px / iPhone viewport)

### Navbar

| Before | After |
|--------|-------|
|
![before-navbar](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/before-navbar.png)
|
![after-navbar](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/after-navbar.png)
|

Before: nav links (Workspaces, Templates, Tasks, Agents) are always
visible, overflowing the mobile header and pushing the hamburger menu
off-screen. After: nav links are hidden below `md`; only the logo and
right-side controls are shown.

### Mobile menu

| Before | After |
|--------|-------|
|
![before-mobile-menu](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/before-mobile-menu-open.png)
|
![after-mobile-menu](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/after-mobile-menu-open.png)
|

Before: hamburger menu had no navigation links. After: Workspaces,
Templates, and Agents links appear at the top of the dropdown.

### Agents sidebar

| Before | After |
|--------|-------|
|
![before-agents-sidebar](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/before-agents-sidebar.png)
|
![after-agents-sidebar](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/after-agents-sidebar.png)
|

Before: the Coder logo/back-link in the sidebar header was hidden on
mobile (`hidden md:block`). After: always visible, giving mobile users a
way to navigate back.

### Workspace page

| Before | After |
|--------|-------|
|
![before-workspace](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/before-workspace.png)
|
![after-workspace](https://raw.githubusercontent.com/coder/coder/mobile-screenshots/.github/pr-screenshots/after-workspace.png)
|

Before: `p-8` (32px) on all sides at every viewport. After: `p-4` (16px)
on mobile, `p-8` at `md` and above.

---

> Generated by Coder Agent
2026-04-30 11:32:40 -05:00
Dean Sheather e57525002c chore: remove agents experiment flag and mark feature as beta (#24432)
Remove the `ExperimentAgents` feature flag so the Agents feature is
always available without requiring `--experiments=agents`. The feature
is now in beta.

Existing deployments that still pass `--experiments=agents` will get a
harmless "ignoring unknown experiment" warning on startup.

### Changes

**Backend:**
- Remove `RequireExperimentWithDevBypass` middleware from chat and MCP
server routes
- Always include `AgentsAccessRole` in assignable site roles (later
refactored to org-scoped on main; rebase keeps that)
- Always set `AgentsTabVisible = true`, then drop the entire dead
`AgentsTabVisible` metadata pipeline (Go htmlState field,
populateHTMLState goroutine, HTML meta tag, useEmbeddedMetadata
registration, mock); no production consumer reads it. `AgentsNavItem`
already gates on `permissions.createChat`.
- Make `blob:` CSP `img-src` addition unconditional
- Remove `ExperimentAgents` constant, `DisplayName` case, and
`ExperimentsKnown` entry

**CLI:**
- Graduate the agents TUI from `coder exp agents` to `coder agents`
(moved from `AGPLExperimental()` to `CoreSubcommands()`)
- Drop the `agent` alias so it does not collide with the hidden
workspace-agent command
- Rename implementation files `cli/exp_agents_*.go` -> `cli/agents_*.go`
and internal identifiers (`expChatsTUIModel` -> `chatsTUIModel`,
`newExpChatsTUIModel` -> `newChatsTUIModel`, `setupExpAgentsBackend` ->
`setupAgentsBackend`, `startExpAgentsSession` -> `startAgentsSession`,
`expAgentsPtr` -> `agentsPtr`, `expAgentsSession` -> `agentsSession`,
`TestExpAgents*` -> `TestAgents*`). `expClient` (the
`*codersdk.ExperimentalClient` local) is kept; `coderd/exp_chats*.go`
and other still-experimental `cli/exp_*.go` commands are intentionally
untouched.

**Frontend:**
- Remove experiment check from `AgentsNavItem` - render when
`canCreateChat` is true
- Remove `agentsEnabled` experiment check from `WorkspacesPage`, then
gate `chatsByWorkspace` on `permissions.createChat` so users without
chat access don't trigger the per-page DB query (Copilot review
feedback)
- Add `FeatureStageBadge` (beta) next to the Coder logo in the Agents
sidebar (desktop + mobile)

**Docs:**
- Remove experiment flag setup instructions from `early-access.md` and
`getting-started.md` (and rename `early-access.md`'s "Enable Coder
Agents" heading to "Set up Coder Agents", since there is no enablement
step left)
- Update `chats-api.md` and `getting-started.md`'s Chats API note to say
"beta" instead of "experimental"
- `docs/manifest.json`: drop "experimental" from the Chats API sidebar
description
- `make gen` regenerated `docs/reference/cli/agents.md` and the CLI
index
- `scripts/check_emdash.sh`: exclude `cli/testdata/*.golden` and
`enterprise/cli/testdata/*.golden` from the new repo-wide emdash lint,
since serpent emits emdash borders in every generated `--help` golden
file

**Tests:**
- Remove `ExperimentAgents` setup from all test files (14 occurrences
across 7 files)
- Update stale "with the agents experiment" comments in
`coderd/x/chatd/integration_test.go` and `coderd/mcp_test.go`


<img width="1185" height="900" alt="image"
src="https://github.com/user-attachments/assets/b420bc8f-41d6-42c6-abd8-ad572533d651"
/>


> 🤖 Generated by Coder Agents
2026-05-01 01:49:00 +10:00
Danny Kopping b975262a97 fix(site): remove Request Logs from admin menu, redirect /aibridge to sessions (#24840)
*Disclaimer: implemented by a Coder Agent using Claude Opus 4.6*

Remove the "AI Bridge Logs" menu item from the Admin settings dropdown,
keeping only the "AI Bridge Sessions" link. The `/aibridge` index now
redirects to `/aibridge/sessions` instead of `/aibridge/request-logs`.

The request-logs route and view remain accessible via direct URL
(`/aibridge/request-logs`) for users who still need it.

Fixes https://linear.app/codercom/issue/AIGOV-205

<details><summary>Changes</summary>

- `DeploymentDropdown.tsx`: Removed "AI Bridge Logs" menu item; the
`canViewAIBridge` block now only renders the "AI Bridge Sessions" link
- `router.tsx`: Changed `/aibridge` index redirect from `request-logs`
to `/aibridge/sessions`
- All request-logs page files, route, and components are preserved for
direct URL access

</details>
2026-04-30 10:04:20 -05:00
George K 25ae415481 fix(site): fix download log size display (#24758)
Previously, the workspace "Download logs" dialog formatted the original byte
count with the promoted unit, so sizes above 1 KiB could be shown incorrectly,
for example `4472 KB` instead of `4.37 KB`. Exact 1024-byte files also stayed
in bytes.
2026-04-29 10:52:01 -07:00
Kayla はなandJake Howell 5afb297042 refactor(site): remove Stack component (#24503)
## Summary

Remove the deprecated `Stack` component and replace all usages with
Tailwind flex utility classes.

- Replaced `<Stack>` → `<div className="flex flex-col gap-4">` (and
variants per props)
- Updated `StackLabel` and `FormFields` to no longer depend on `Stack`
- Deleted `Stack.tsx` and `Stack.stories.tsx`

74 files changed, -226 lines net.

> 🤖 Generated by Coder Agents

---------

Co-authored-by: Jake Howell <jacob@coder.com>
2026-04-28 12:02:13 -06:00
Kayla はな d78a78ffa1 refactor(site): drop redundant window. prefix on browser globals (#24500) 2026-04-27 15:06:39 -06:00
Seth ShelnuttandJakub Domeracki 66abd8a271 fix(site): require confirmation before executing terminal command from URL (#24650)
The terminal page auto-executed commands from the `?command=` query
parameter
on page load without user confirmation. Because session auth uses
`SameSite=Lax`
cookies, an attacker could craft a link (phishing email, Slack DM,
external page)
that executes arbitrary commands in a victim's workspace when clicked.

Adds a `ConfirmDialog` that shows the exact command and requires
explicit user
approval before it is passed to the terminal WebSocket. Canceling
removes the
`command` parameter from the URL and opens a plain terminal.

<details>
<summary>Implementation details</summary>

### Data flow (before)

`TerminalPage.tsx` reads `searchParams.get("command")` and passes it
directly
as `initialCommand` to `WorkspaceTerminal`, which embeds it in the
WebSocket
URL. `proxy.go` forwards it to the agent, which runs `bash -c
"<command>"`
immediately.

### Fix

- Added `commandConfirmed` state and `commandPendingConfirmation` flag
in
  `TerminalPage.tsx`.
- The `loading` prop passed to `WorkspaceTerminal` includes
`commandPendingConfirmation`, keeping the terminal in loading state
until
  the user confirms or cancels.
- The command is only passed as `initialCommand` after the user clicks
  "Run command" in the confirmation dialog.
- Trusted `?app=` commands (resolved from agent apps) bypass the dialog.
- Cancel removes the `?command=` parameter from the URL entirely.
- No backend changes needed; the frontend gates the command before it
  reaches the WebSocket.

### Terminal focus after dialog

`WorkspaceTerminal`'s autoFocus effect previously depended on
`[terminal, isVisible, autoFocus]` but not `loading`. It fired while the
Radix dialog's focus trap was active, so `terminal.focus()` was
intercepted. When `loading` became false after confirming the dialog,
the
effect did not re-fire. Fixed by adding `loading` to the effect deps and
skipping focus while `loading` is true.

### Files changed

| File | Change |
|------|--------|
| `site/src/pages/TerminalPage/TerminalPage.tsx` | Confirmation dialog,
`commandPendingConfirmation` in loading prop |
| `site/src/pages/TerminalPage/TerminalCommandConsentDialog.tsx` | New
dialog component |
| `site/src/pages/TerminalPage/TerminalCommandConsentDialog.stories.tsx`
| Storybook story for dialog |
| `site/src/pages/TerminalPage/TerminalPage.stories.tsx` |
`CommandConfirmation` story |
| `site/src/pages/TerminalPage/TerminalPage.test.tsx` | 4 new dialog
tests, `renderTerminalRaw` helper for non-blocking render |
| `site/src/modules/terminal/WorkspaceTerminal.tsx` | Add `loading` to
autoFocus effect deps |
| `site/e2e/helpers.ts` | Dismiss dialog in `openTerminalWindow` helper
|
| `site/e2e/tests/webTerminal.spec.ts` | Wait for
`data-status="connected"` + click terminal for focus |

</details>

> 🤖 Generated by Coder Agents

---------

Co-authored-by: Jakub Domeracki <jakub@coder.com>
2026-04-27 15:11:45 +02:00
Jake Howell 056203f8fc fix: resolve outsideBox style for tabs (#24561)
> 🤖 This PR was modified by Coder Agents on behalf of Jake Howell.

Fixes the `outsideBox` variant styling for tabs and simplifies the kebab
overflow logic. The overflow calculation now accounts for `column-gap`
between tabs so the menu trigger appears at the correct breakpoint.

- Fix Tailwind hover selector syntax for `outsideBox` variant
(`[&_[data-slot=tabs-trigger]:hover]` instead of
`[&_[data-slot=tabs-trigger]]:hover`)
- Account for `column-gap` in `useKebabMenu` overflow calculation via a
new `getTabGap` helper
- Use content-box width (`getContentBoxWidth`) for the initial overflow
pass so it matches `ResizeObserver`'s `contentRect.width`
- Consolidate `calculateTabValues` into a single-pass loop, removing the
separate `findFirstTabIndex` function
- Drop `FC` wrapper in favor of inline prop destructuring across all tab
components
- Forward `ref` through `TabsList` so consumers can attach refs directly
- Add `useKebabMenu` unit tests covering both all-visible and overflow
scenarios
2026-04-25 11:32:04 +10:00
Asher d958d89b6f fix: do not clobber dynamic parameters (#24645)
Once a user has touched a field, it is better to leave it alone and display explicit validation errors over silently overwriting their inputs.  Same for auto-filled values (whether from query parameters or a previous build).
2026-04-24 11:26:04 -08:00
Hugo Dutka c56061a09d fix(site): focus agents terminal on tab switch (#24677)
Fixes
[CODAGT-221](https://linear.app/codercom/issue/CODAGT-221/terminal-selection-in-side-panel-does-not-focus-input).
Verified manually that the fix automatically focuses the terminal input
when the terminal tab is selected.
2026-04-23 18:36:46 +02:00
Jake Howell 4caa52844d chore!: remove api.ts unnecessary calls (#22168)
> [!WARNING]  
> The change of the status code from `404` to `204` could break peoples
code downstream. Adding this as a breaking change incase.

Theres a whole ton of noise around failed requests, these are all
unrelated to the actual thing that is broken at hand (and are
confusing).

* Change `/api/v2/organizations/.../templates/.../versions/.../previous`
to return `204` instead of `404` (actually makes more sense because the
content doesn't exist, but the route is found.
* Remove unnecessary calls to `/api/v2/users/me/appearance` when the
user isn't logged in.
* Remove unnecessary calls to `/api/v2/deployment/stats` when the
deployment stats aren't allowed to be seen.
* Various changes to `workspace-sharing` so we don't make unnecessary
calls.

Whats left:

* `/api/v2/users/me` still `401`s on the login page. This persists as
when the user is logged in but tries to reach the sign-in page they
should be redirected to the app, not sign in again.
* `monaco-editor` is still upset... we theoretically could inject an
environment that can serve workers... but eh.

#### Old

```sh
% pnpm playwright:test -g "create workspace with default and required parameters"

> coder-v2@ playwright:test /home/coder/coder/site
> playwright test --config=e2e/playwright.config.ts -g 'create workspace with default and required parameters'

...

Running 2 tests using 1 worker

  ✓  1 …e/setup/addUsersAndLicense.spec.ts:7:5 › setup deployment (8.2s)
     2 ….ts:79:5 › create workspace with default and required parameters
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
[console][error] Failed to load resource: the server responded with a status of 404 (Not Found)
[response] url=http://localhost:3111/api/v2/organizations//provisionerdaemons status=404 body={"message":"Resource not found or you do not have access to this resource"}
[console][error] Failed to load resource: the server responded with a status of 404 (Not Found)
[response] url=http://localhost:3111/api/v2/organizations/default/templates/a4e8096d/versions/agreeable_glenn33/previous status=404 body={"message":"No previous template version found for \"agreeable_glenn33\"."}
[console][warning] Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq
[console][warning] You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
  ✓  2 …5 › create workspace with default and required parameters (7.0s)atus of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}

  2 passed (56.1s)
```

`23 LOL` (Lines of logs)

#### New

```sh
% pnpm playwright:test -g "create workspace with default and required parameters"

> coder-v2@ playwright:test /home/coder/coder/site
> playwright test --config=e2e/playwright.config.ts -g 'create workspace with default and required parameters'

...

Running 2 tests using 1 worker

  ✓  1 …e/setup/addUsersAndLicense.spec.ts:7:5 › setup deployment (8.7s)
     2 ….ts:79:5 › create workspace with default and required parameters
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[console][warning] Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq
[console][warning] You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker
  ✓  2 …5 › create workspace with default and required parameters (7.1s)atus of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}

  2 passed (32.0s)
```

`9 LOL` (Lines of logs)
2026-04-23 06:20:35 +10:00
Michael Suchacz 60186b2489 refactor(site/src): split Agent Settings Behavior into focused destinations (#24574)
Reorganizes Agents Settings navigation. Previously a flat sidebar with
admin items gated by a role check; now a two-level drill-down with user
settings at the top and admin destinations nested under a "Manage
Agents" sub-panel.

**Top Settings panel** (all users, sidebar title "Settings"):

| Destination | Route |
| --- | --- |
| General | `/agents/settings/general` |
| Compaction | `/agents/settings/compaction` |
| Secrets (API keys) | `/agents/settings/api-keys` |
| Manage Agents › (admin only) | drills into the admin sub-panel |

**Manage Agents sub-panel** (admin only, sidebar title "Manage Agents"):

| Destination | Route |
| --- | --- |
| Agents | `/agents/settings/agents` |
| Providers | `/agents/settings/providers` |
| Models | `/agents/settings/models` |
| MCP Servers | `/agents/settings/mcp-servers` |
| Templates | `/agents/settings/templates` |
| Spend | `/agents/settings/spend` |
| Instructions | `/agents/settings/instructions` |
| Experiments | `/agents/settings/experiments` |
| Lifecycle | `/agents/settings/lifecycle` |
| Insights | `/agents/settings/insights` |

On mobile, tapping "Manage Agents" lands on `/agents/settings/admin`, an
admin sub-panel index URL that shows the admin nav in the sidebar (so
admins can still reach every admin destination without desktop-width
viewports).

Key changes:

- **Split the monolithic Behavior page into five focused destinations**
(General, Compaction, Instructions, Experiments, Lifecycle) so non-admin
users no longer trigger deployment-scoped queries like
`chatSystemPrompt`, `chatDesktopEnabled`, or `chatWorkspaceTTL`.
Admin-only pages gate both route (via `RequirePermission`) and query
`enabled` flags.
- **Split chat debug logging into audience-specific components** so no
admin-gated controls remain in user-facing pages.
`AdminChatDebugLoggingSettings` (admin "Let users record chat debug
logs") now lives in the Experiments tab; `UserChatDebugLoggingSettings`
("Record debug logs for my chats") stays in General and only renders
when the admin has allowed user-level toggling.
- **Nested admin sub-panel** in the sidebar. `SidebarView` gains a
`"settings-admin"` panel; `sidebarViewFromPath` routes admin sections
into it. The slide animation and back button behavior extend cleanly. A
small `isSettingsView` helper was extracted alongside to avoid
duplicating the panel-membership check.
- **Renamed `/agents/settings/system-instructions` to
`/agents/settings/instructions`**. Sidebar label is "Instructions". Page
files renamed to `AgentSettingsInstructionsPage(View)` to match the
route slug (the other split pages all do).
- **Renamed "API Keys" to "Secrets (API keys)"** in the sidebar and page
header.
- **Added MCP Servers** entry to the sidebar (route already existed).
- **Added "Manage Coder Agents"** link at the bottom of the Deployment
settings sidebar (gated by `editDeploymentConfig`, matches the existing
`Groups ↗` external-link style).
- **Updated icons** across the sidebar: General uses `UserIcon`,
Compaction `ShrinkIcon`, Secrets `KeyIcon`, Manage Agents
`Settings2Icon`, Providers `PlugIcon`, MCP Servers `ServerIcon`, Spend
`CoinsIcon`, Instructions `ReceiptTextIcon`, Lifecycle `RefreshCwIcon`,
Insights `SparklesIcon`.
- **Storybook interaction coverage** restored and extended for the split
views: user-prompt save flow, invisible-Unicode warning detection,
system-prompt default toggle, workspace-TTL validation, virtual-desktop
toggle, compaction threshold save/reset/validation, retention
toggle/save-error/load-error parity, plan-mode instructions save, and a
mobile story verifying the admin sub-panel remains reachable after the
"Manage Agents" tap.
- **Unit tests** added for `sidebarViewFromPath` and `isSettingsView`
(17 cases covering chats, analytics, user sections, admin sections, the
new `/admin` index, non-admin fallthrough, and defaults).

> Mux opened this PR on behalf of Mike.
2026-04-22 17:45:29 +02:00
Jeremy RuppelandClaude Sonnet 4.6 b4eb0e20e5 fix(site): show startup script failure message without restart suggestion (#24449)
When a workspace agent's startup script fails, restarting the workspace
will not resolve the issue since the script will keep failing.
Previously all unhealthy workspaces showed the same generic notification
with a Restart button regardless of cause.

Now, when every failing agent has `lifecycle_state=start_error`, the
workspace-level notification shows "A startup script has failed" and
guides the user to contact their template admin instead of offering a
Restart action.

> Code written by Claude 🤖 reviewed by yours truly

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 10:40:32 -04:00
Jake Howell 3466806a66 fix(site): implement agent logs improvements (#24455)
Polishes the agent logs panel in the workspace resources UI: consistent
padding, clearer behavior when switching log source tabs, and a more
usable download menu for long source lists.

- Use symmetric vertical padding on the logs container (`py-4` instead
of top-only padding).
- Add optional `showSourceIcons` on `AgentLogs` (defaults on);
`AgentRow` turns it off unless the **All** tab is active so filtered
tabs are not cluttered with redundant source icons.
- Anchor the download-logs dropdown below the trigger and cap menu
height to 6 items with scrolling so many sources do not overflow the
viewport.
2026-04-21 03:49:50 +00:00
Jake Howell 67c57abb63 chore: tighten .vscode IDE and typescript configuration (#24537)
This branch tightens import hygiene and editor guidance to reduce
accidental use of legacy or discouraged patterns.
It also updates consumers too, by propagating the new `lucide-react`
import convention across the existing UI surfaces that reference those
icons.

- Updated `.vscode/settings.json` to prefer non-relative imports and
improve TypeScript auto-import behavior.
- Re-enabled and expanded Biome restricted-import enforcement in
`biome.jsonc` for migration guardrails.
- Added/used `lucide-react` `-Icon` naming conventions for clarity and
consistency.
- Updated consumers too across components, modules, and pages so the new
import rules are applied end-to-end.
2026-04-21 13:45:08 +10:00