Commit Graph
4457 Commits
Author SHA1 Message Date
Ethan ac8cda66f7 feat: make Coder Agents right sidebar app and port tabs generally available (#26906)
The workspace-app and port preview tabs in the Coder Agents right panel
were gated behind the `agent-app-tabs` deployment experiment. This
removes the experiment entirely and renders the app and port tabs
unconditionally, so the add-panel dropdown, workspace-app tabs, and port
preview tabs are always available alongside terminals.

## Changes

- Remove the `ExperimentAgentAppTabs` constant, its `DisplayName()`
case, and its `ExperimentsKnown` registration in
`codersdk/deployment.go`, then regenerate
`site/src/api/typesGenerated.ts`, `coderd/apidoc/docs.go`,
`coderd/apidoc/swagger.json`, and `docs/reference/api/schemas.md`.
- Drop the frontend experiment gate in `AgentChatPageView.tsx`
(including the now-unused `useDashboard`/`experiments` usage) so
persisted app and port tabs are no longer filtered out.
- Remove the `appExperimentEnabled` prop from `RightPanelAddTabControl`
and render the add-panel dropdown unconditionally; update the stories
accordingly.

This reverses the gating introduced in #26395.

note: the diff is tiny if you hide whitespace changes
2026-07-01 16:58:10 +10:00
Jake Howell cb1a87b9c0 fix(site): stop click propagation so popover opens inside clickable rows (#26875)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

<img width="628" height="353" alt="image"
src="https://github.com/user-attachments/assets/16fbf58f-282a-4629-b0de-45160117adb6"
/>

Linear:
[DES-22051](https://linear.app/codercom/issue/DES-22051/adjust-workspace-list-icon-and-agent-link-affordance)

## Problem

[#23374](https://github.com/coder/coder/pull/23374) swapped the
underlying `Tooltip` for a `Popover` under the `HelpTooltip` →
`HelpPopover` rename, turning the trigger from a hover surface into a
click surface.

On the workspaces list, `WorkspaceOutdatedTooltip` is rendered inside a
`<TableRow>` wired up by `useClickableTableRow`, whose `onClick`
navigates to the workspace page. Other interactive children in the same
row already stop propagation (checkbox, actions cell, agent badge). The
outdated tooltip didn't, so clicking the info icon bubbled up to the
row's `onClick` and navigated away before the popover could open.

## Fix

Stop click and keydown propagation on both trigger variants
(`HelpPopoverTrigger asChild` span and `HelpPopoverIconTrigger`) in
`WorkspaceOutdatedTooltip`. The popover still opens because Radix
composes its own click handler on top of the user-provided one via
`composeEventHandlers`; `stopPropagation()` does not set
`defaultPrevented`, so Radix's toggle still runs.

## Regression coverage

Added an `InsideClickableRow` story that mounts the tooltip inside a
`useClickableTableRow` row with a tracked `onRowClick`, clicks the
trigger, asserts the popover dialog opens, and asserts `onRowClick` was
not called. Verified locally that the new story fails on `main` (1 call
to `onRowClick`) and passes with this fix.

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

- Fix lives on the component (rather than at the `WorkspacesTable.tsx`
call site) so every consumer is safe by default. The popover is
interactive in a way the parent shouldn't have to know about, and the
existing call site in `TaskPage.tsx` is unaffected because its parent
has no click handler.
- `onKeyDown` propagation is also stopped so the trigger keeps working
when activated via keyboard, and to satisfy
`lint/a11y/useKeyWithClickEvents` on the `<span>` trigger variant.
- Considered pushing the guard down into the `HelpPopoverIconTrigger` /
`HelpPopover` primitives so every consumer is covered — left as a
separate follow-up since today only `WorkspaceOutdatedTooltip` is
embedded in a `useClickableTableRow` row, and a blanket change would
need a broader audit.

</details>
2026-07-01 03:21:26 +00:00
Jeremy Ruppel a73e677639 fix: several UI fixes for Template Builder (#26903)
- Module selection summary now has `rounded-sm` corners to fit the icon
- Modules without configuration now say so with a check mark
- Correct "Additional settings" label
2026-06-30 20:01:48 -04:00
Jeremy Ruppel c56a8f1d99 feat(site/src/pages/TemplateBuilder): add scroll overflow and sticky sidebar to wizard steps (#26881)
Add vertical overflow scrolling to the TemplateBuilder wizard step
content areas and make the selection sidebar sticky.

## Changes

- **Scroll on inner content**: Each step's inner content area (below the
heading and any tabs/search) gets `max-h-[calc(100vh-Npx)]
overflow-y-auto`, keeping headings and tab bars visible while the
content scrolls.
- Base template select and module select grids: 420px offset (accounts
for navbar, page header, card padding, tab bar, and nav controls)
  - Base template parameters and module settings: 340px offset
  - Customizations step: no scroll, flows naturally
- **Sticky sidebar**: The selection summary sidebar uses `sticky top-0
self-start` to stay visible while scrolling.
- **Scroll reset on navigation**: `window.scrollTo(0, 0)` in
Back/Continue handlers so users start at the top of each step.

> 🤖 Generated by Coder Agents

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

The approach uses `max-h` with `overflow-y-auto` on the inner content
divs of each step component, placed below the step heading and any
tabs/search controls. This keeps the heading fixed while the content
scrolls. The offset values account for the vertical space consumed by
the navbar, page header, card border/padding, and navigation controls.

The `DashboardFullPage` flex-fill approach was explored but abandoned
because the viewport-constrained card was too short to show content on
smaller screens. The standard `Margins` + `pb-12` layout with per-step
`max-h` provides a better balance.
</details>
2026-06-30 20:00:56 -04:00
Andrew Aquino 15d4eb9db8 feat(site): use template/module config variable's default value as its field placeholder if present (#26880)
closes DEVEX-543

Previously, templates'/modules' config variables' input fields would
just display Required/Optional as placeholder text. Now we show the
field's default value as a placeholder if defined
([example](https://github.com/coder/coder/blob/496c0576ca6bfbf3ba4b8d470cd320549f7fc6d1/coderd/templatebuilder/modules/aider/module.json#L30)),
falling back to Required/Optional if there's no default defined.

599b607194 co-authored with Claude Code
2026-06-30 16:01:16 -07:00
Danielle Maywood 6b8c38b5a4 fix: gate chat advisor and virtual desktop behind experiments, delete experiments page (#26809) 2026-06-30 21:57:40 +01:00
Andrew Aquino 7baf0d4a9a fix(site): restore missing avatar padding from TemplateBuilderAvatarData (#26884)
fixes DEVEX-568

The `Avatar` variant I actually wanted for `TemplateBuilderAvatarData`
during #26776 was the compound one with both `size="lg" variant="icon"`,
which includes padding:


https://github.com/coder/coder/blob/2be540e469677e716d48612a5f5d078a8eb35bce/site/src/components/Avatar/Avatar.tsx#L35-L40

Using `Avatar` for `TemplateCard`/`ModuleCard` also ensures that those
components display a theme-appropriate icon image, i.e., light on dark /
dark on light.
2026-06-30 12:08:58 -07:00
TJ 3c889fb384 fix(site/src/pages/AgentsPage): normalize chat menus to a kebab icon and matching items (#26588)
The chat title menu used a horizontal ellipsis (meatball) and a
different set of items than the sidebar chat-row menu. Designers asked
to normalize both menus on the sidebar shape since the sidebar is the
more recent design.

The chat top bar now uses the same `EllipsisVerticalIcon` (kebab) as the
sidebar row and exposes the same items in the same order: Pin/Unpin
agent, Rename chat, Archive agent, and Archive & delete workspace.
Labels are sentence case throughout. The standalone "Generate new title"
item is removed because the rename dialog's Generate button covers the
same workflow, which is what the sidebar already exposes. The kebab now
sits inline with the title rather than off to the right, so it reads as
a title menu instead of a global action.

Both menus render from a single `ChatActionsMenuItems` component so they
cannot drift in the future. The shared component is polymorphic over
`Item` and `Separator`, which lets the sidebar drive both its kebab
(`DropdownMenu`) and its right-click context menu (`ContextMenu`) from
the same JSX.

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

- `ChatActionsMenuItems.tsx`: new shared component. Renders the
Pin/Unpin, Rename, Archive, Archive & delete workspace, and Unarchive
items off a flat set of flags (`isArchived`, `isPinned`, `isChildChat`,
`hasWorkspace`, `isArchiving`) and zero-arg handlers, plus polymorphic
`Item`/`Separator` components.
- `ChatTopBar.tsx`: replace the inline `EllipsisIcon` + duplicated
dropdown body with the kebab trigger and a `<ChatActionsMenuItems>`
call. Move the dropdown trigger into the title area so it sits next to
the title text; switch `DropdownMenuContent` to `align="start"` so the
menu opens flush with the trigger's left edge. Replace the old
`onRegenerateTitle`/`isRegenerateTitleDisabled` props with `onPinAgent`,
`onUnpinAgent`, `onOpenRenameDialog`, `isPinned`, and `isChildChat`.
- `ChatTreeNode.tsx`: delete the inline `renderMenuItems` helper and
call `<ChatActionsMenuItems>` from both the `DropdownMenuContent` and
the `ContextMenuContent`. Pin handlers are pre-bound to `chat.id`;
`onOpenRenameDialog` is pre-bound to the chat object.
- `AgentsPageView.tsx`: lift the rename-chat dialog state up here and
expose it through `AgentsOutletContext.onOpenRenameDialog`, so the
sidebar row menu and the chat top bar open the same dialog instance.
- `ChatsSidebar.tsx`: accept optional controlled
`chatPendingRename`/`onChatPendingRenameChange` props with
internal-state fallback (controlled-or-uncontrolled pattern). Existing
stories and tests are untouched.
- `AgentChatPage.tsx`: consume `requestPinAgent`, `requestUnpinAgent`,
and `onOpenRenameDialog` from the outlet context, and pass new
`handlePinAgentAction`, `handleUnpinAgentAction`,
`handleOpenRenameDialog`, `isPinned`, and `isChildChat` props through
`AgentChatPageView` to the top bar.
- Stories: `ChatTopBar.stories.tsx` replaces the `GenerateTitle` story
with `RenameChatItem`, `PinAgentItem`, `UnpinAgentItem`, and
`ChildChatHidesPinAction`. Updated label expectations to sentence case
across stories. `AgentChatPage.stories.tsx` updated for the new "Archive
agent" label.

</details>

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

- **Source of truth.** Per the designer, the sidebar menu is the
canonical list; the chat title menu is what should change.
- **One menu body.** A shared `ChatActionsMenuItems` component drives
both menus so they cannot drift. Reviewers only need to read the menu
items once.
- **Icon parity.** Both menus now use `EllipsisVerticalIcon` (kebab).
The old meatball was the only `EllipsisIcon` use in this surface.
- **Kebab position.** Moved next to the title so the kebab reads as a
per-chat action against the title, not a global top-bar action. Share
and Toggle-panel stay on the right of the bar.
- **"Generate new title" removed, not preserved as extra.** Keeping it
would have re-introduced the inconsistency the designer is asking to
remove. The rename dialog's Generate button already runs the propose
flow and lets the user accept or edit the suggestion. The
auto-regenerate code path (`requestRegenerateTitle`,
`regeneratingTitleChatIds`, the title spinner) is left in place because
removing it expands the diff and the regenerate plumbing may be re-used;
only the menu trigger is gone.
- **Single dialog instance.** Two separate `RenameChatDialog` instances
would have worked, but lifting the state to `AgentsPageView` keeps a
single source of truth and lets the top bar open the dialog the user
already knows. `ChatsSidebar` keeps internal-state fallback so existing
stories and tests do not need to thread state.
- **`isChildChat`.** Pin/Unpin is hidden for child chats to match
`ChatTreeNode`, which only renders the Pin item when `!isChildNode`.

</details>

<sub>Opened by Coder Agents on behalf of @tracyjohnsonux.</sub>
2026-06-30 11:56:45 -07:00
TJ 2be540e469 feat(site/src/pages/AISettingsPage/ModelsPage): add search and provider filter to models list (#26683)
Adds a search input and provider filter dropdown above the Models table
on `/ai/settings/models`, and moves the `Default` badge to sit beside
the model name.

## Changes

- **Search**: text input matches against model display name, model
identifier, and provider label (case-insensitive).
- **Provider filter**: select dropdown listing every configured
provider, plus an `All providers` default.
- Filters apply before pagination and reset to page one when changed.
- New empty state when filters return no matches.
- Pagination footer now shows the filtered total, with `(filtered from
N)` when filters are active.
- `Default` badge moved from the Status column to inline next to the
model name.
- Stories cover the new search, provider filter, and no-match empty
state.

## Screenshots

Please see the Storybook stories under
`pages/AISettingsPage/ModelsPage/ModelsPageView` for `Default`,
`SearchByName`, `FilterByProvider`, and `NoMatchingModels`.

## Verification

- `pnpm --dir site exec biome check
src/pages/AISettingsPage/ModelsPage/`
- `pnpm --dir site exec tsc -p . --noEmit`
- `pnpm --dir site test:storybook -- --project=chromium
src/pages/AISettingsPage/ModelsPage/` (8/8 ModelsPageView stories pass;
the unrelated `MCP Tool Completed` failure under
`AgentsPage/components/ChatElements` reproduces on `main`)

---

> [!NOTE]
> Opened by Coder Agents on behalf of @tracyjohnsonux.
2026-06-30 11:34:14 -07:00
Paweł Banaszewski 377c1309b7 chore: hide AI Gateway key management UI/CLI/API (#26879)
Hides UI, CLI and API related to AI Gateway key management +
`/api/v2/ai-gateway/serve` endpoint.
API endpoints and CLI commands are still working they are just not
visible.
2026-06-30 17:32:38 +00:00
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
Danielle Maywood 496c0576ca fix(site): rename model action to Set as Coder Agents default model (#26872) 2026-06-30 17:22:57 +01:00
Danielle Maywood 7234b5667b fix(site): autosave personal model overrides toggle (#26871) 2026-06-30 17:22:28 +01:00
Jeremy Ruppel a153b77fa5 feat(site/src/pages/TemplateBuilder): add alternatives box to base template step (#26878)
Adds an "Alternatives to create a template" section below the navigation
controls on the base infrastructure selection step of the Template
Builder wizard. The box is only shown on the first step and contains
four outline buttons linking to other template creation paths:

- **Start from scratch** -> Coder docs tutorial (external)
- **Upload an existing template** -> `/starter-templates` (internal)
- **Browse community templates** -> Registry templates (external)
- **Use template agent skill** -> Registry skills (external)

External links open in a new tab with an external-link icon.

Closes [DEVEX-564](https://linear.app/codercom/issue/DEVEX-564)

> [!NOTE]
> This PR was authored by Coder Agents on behalf of @jeremyruppel.

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

### 1. `TemplateAlternatives.tsx` (new)
- Presentational component rendering a bordered container with label and
four `Button` components (variant `outline`, size `sm`)
- External links use `ExternalLinkIcon` from lucide-react and open in
`_blank`
- Internal link uses React Router `Link`

### 2. `TemplateBuilderPageView.tsx` (modified)
- Import and render `<TemplateAlternatives />` below navigation
controls, conditionally when `currentStep.id === "base-infra"`

### 3. `TemplateAlternatives.stories.tsx` (new)
- Default Storybook story for the component

</details>
2026-06-30 16:02:06 +00: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
Jake Howell a79fcd34af feat: implement <WorkspaceDeletedBanner /> on <WorkspaceBuildPage /> (#25664)
Closes #24731 

This pull-request attempts to pull the workspace when it has been
deleted, as to not show a generic error on the `<WorkspaceBuildPage />`.
This secondary query for the workspace is only initiated if we get an
error from the build itself, this is to ascertain if there actually was
a workspace here previously or if we are actually 404ing.

Future improvements might be to `410 Gone` these workspaces/builds.
2026-06-30 15:29:28 +00:00
Jon Ayers 538eddb731 feat: add dashboard fields for configuring autostop reminder (#26762) 2026-06-29 18:28:23 -05:00
Jeremy Ruppel 1a07bd65d4 feat(site): wire template builder entrypoint from templates list page (#26756)
The templates list page "New template" button and the empty-state "View
all starter templates" button now link to `/templates/new/builder` when
the template builder is enabled in the deployment config, falling back
to `/starter-templates` when disabled.

The `TemplateBuilderPage` now checks `createTemplates` permission and
redirects to `/templates` if the user lacks access. The
`templateBuilderBases` query is also gated on `enabled` to avoid a 404
when the feature is disabled.

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

- `TemplatesPage` fetches `deploymentConfig()` (only when user has
`createTemplates` permission) and computes `templateBuilderEnabled`
using `=== false` to default safely while loading.
- `templateBuilderEnabled` is threaded through `TemplatesPageView` and
`EmptyTemplates` to conditionally set link targets.
- `TemplateBuilderPage` uses `useAuthenticated()` to check
`permissions.createTemplates` before rendering.
- Added Storybook story variants for the builder-enabled state.

</details>

> Generated by Coder Agents on behalf of @jeremyruppel
2026-06-29 19:03:33 -04:00
Jeremy Ruppel a073273a3f feat(site/src/pages/TemplateBuilder): add loading animation for template creation (#26830) 2026-06-29 18:50:29 -04:00
Jeremy Ruppel 431219a5e7 feat(site): add official badge to TemplateCard and ModuleCard (#26806)
Adds an `official` prop to both `TemplateCard` and `ModuleCard` in the
TemplateBuilder. When true (the default), a `BadgeCheckIcon` from
lucide-react is rendered inline next to the card name.

- `official` defaults to `true` since all current templates/modules are
official
- Pass `official={false}` for community entries to hide the badge
- Added `Community` and `CommunitySelected` stories for both components

> Generated by Coder Agents on behalf of @jeremyruppel

<img width="678" height="262" alt="Screenshot 2026-06-29 at 9 38 44 AM"
src="https://github.com/user-attachments/assets/51d1ddad-2bae-4ec3-a1bb-e518c86fa50c"
/>
2026-06-29 18:25:03 -04:00
Jeremy Ruppel 7daf3123cb feat: import new modules and refactor codegen script (#26838) 2026-06-29 17:47:06 -04:00
Jeremy Ruppel 9f7caa04f9 feat(site/src/pages/TemplateBuilder): prioritize template builder module display order (#26835)
Adds a curated priority ordering for modules in the template builder
module picker. Modules in the priority list appear first in the
specified order; unlisted modules appear after in their original order.

## Changes

- Added `MODULE_PRIORITY` constant in `ModuleSelectStep.tsx` with the
preferred display order
- Added `sortByPriority()` helper to sort modules against the priority
list
- Not-yet-imported module IDs (`codex`, `antigravity`, `kasmvnc`) are
included but commented out
- Both the module grid and category tabs respect the new ordering
- Search results still use fuzzy relevance ordering

> Generated by Coder Agents on behalf of @jeremyruppel
2026-06-29 17:04:26 -04:00
Andrew Aquino 1c09c3fca6 fix(site): reduce prerequisites markdown font size (#26776)
closes DEVEX-517
alternative to #26759

This PR is mainly about the type style overrides I added to
`MemoizedMarkdown` in BaseTemplateParametersStep.tsx‎.

I did also shoehorn some other misc styling updates into this PR, but
they're only scoped to template builder so I'll keep it as 1 PR instead
of making a Graphite stack:

- 1b98ac374f: adjusted `StepDivider`'s
left margin which I missed during #26757
- f1eb921048: refactored
templates/modules' avatars to use an `AvatarData` component, so that the
text appears to the right of the avatar instead of below it
2026-06-29 14:38:56 -04: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 60a56cf343 fix(site): use large avatar on provider table (#26804) 2026-06-29 11:49:25 +00:00
Danielle Maywood 3d1e41c616 feat(site): add paginated query options (#26802) 2026-06-29 11:45:28 +01:00
Cian Johnston 86a7bc9fb0 fix: resolve model config provider via ai_provider_id (#26660)
-  `site/src/pages/AISettingsPage/ProvidersPage/components/providerFormApiMap.ts`):
`providerFormValuesToCreate` returns `type: "bedrock"` when the form
type is `bedrock`, instead of `type: "anthropic"` with Bedrock settings.
- Updated `providerFormApiMap.test.ts` to expect `type:
"bedrock"` and `MockAIProviderBedrock` fixture in `entities.ts` to
`type: "bedrock"`. Added Bedrock fixtures to `ModelsPageView` stories
asserting the AWS Bedrock icon renders correctly.

Refs: [CODAGT-549](https://linear.app/codercom/issue/CODAGT-549/bedrock-models-use-anthropic-styling-and-icons)

> 🤖
2026-06-29 11:04:58 +01:00
Danielle Maywood 72980d3e65 refactor(site): share confirm delete dialog (#26799) 2026-06-29 11:00:49 +01:00
Ethan 4820cbf7b1 test: migrate CreateUserPage tests to Storybook play stories (#26794)
Migrates the CreateUserPage tests from vitest to Storybook play-function
stories.

The old `CreateUserPage.test.tsx` rendered the full page through
`renderWithAuth` and MSW, which is slow and contributes to `test-js`
timeout flakes. The new stories seed the react-query cache directly and
assert the same behavior in `play` functions, so they run in the
Storybook test lane instead of the vitest `unit` project.

Coverage is preserved: a success story asserts the success toast after
creating a user, and an error story asserts that an API failure surfaces
in the form's error alert.

Relates to CODAGT-686
Relates to https://github.com/coder/internal/issues/1598
2026-06-29 18:24:23 +10:00
Ehab Younes c782cbce77 feat(site/src/pages/GroupsPage): update group AI budget UI (#26659)
Update the group AI budget settings UI to match the unlimited,
no-budget, and finite-budget states. The field now uses a USD input
suffix, the label reads "Monthly limit per member", and unlimited or $0
budgets show explanatory helper text with an info alert.
2026-06-29 00:52:47 +03:00
McKayla はな 9efbcc7601 chore: make dynamic parameters WorkspaceParametersPage the default (#25095) 2026-06-26 17:55:34 -06:00
McKayla はな efd93027ce feat: allow editing user avatars (#26652)
Adds an avatar URL field to the admin **Edit user** page, available only
for users whose login type is `password` or `none`.

For identity-provider login types (`github`, `oidc`) the avatar is
synced from the IdP on every login, so the field is hidden and the API
ignores any submitted avatar to avoid confusing overwrites.

The field reuses the same emoji picker + URL input (`IconField`) already
used for template, group, and organization icons.

A follow-up PR will add the same control to the self-service Account
settings page.

<details>
<summary>Implementation plan & decisions</summary>

**Goal:** Let an admin set/clear a user's avatar from the Edit user
page, gated to `password`/`none` login types.

**Backend**
- Add `avatar_url` to `codersdk.UpdateUserProfileRequest`.
- `putUserProfile` applies the submitted avatar only for
`password`/`none`; otherwise it preserves the existing (IdP-synced)
value.
- Regenerated TS types and API docs via `make gen`.

**Frontend**
- `EditUserForm` renders an `IconField` ("Avatar URL") when the login
type allows it.
- `EditUserPage` passes the avatar value and a `canEditAvatar` flag.
- `AccountPage` round-trips `avatar_url` so the shared request type
doesn't wipe avatars on the self-service path.

**Gating** is enforced in both the UI (field hidden) and the backend
(submitted value ignored for IdP login types).

**Tests/stories:** backend `TestUpdateUserProfile` covers apply
(password) and ignore (SSO); `EditUserForm` stories cover the
shown/hidden states with interaction tests.

</details>

---
> Generated by Coder Agents on behalf of @aslilac.
2026-06-26 16:35:03 -06:00
McKayla はな 7481e1a5a0 fix(site): keep TemplateVersionEditor file tree in sync (#25068) 2026-06-26 14:47:55 -06:00
Andrew Aquino e24bc5b572 refactor(site): use our Link component in Markdown instead of MUI (#26758)
ref DEVEX-517

MUI's `Link` color does not come from our design system, whereas our
`Link`'s does
2026-06-26 12:35:17 -07:00
Andrew Aquino 2ba85d9657 feat(site): give all template builder steps rounded border + padding (#26757)
ref DEVEX-517

Some small preliminary UI spruce-ups to get each step closer to the
design before implementing the main feature for DEVEX-517. See commit
messages for individual changes.

The most prominent change is making it so that every step gets wrapped
in this rounded/bordered/padded container. Previously it was present
only in `ModuleSettingsStep` and `TemplateCustomizationsStep`; but
missing from `BaseInfraSelectStep`, `BaseTemplateParametersStep`, and
`ModuleSelectStep`

<img width="1840" height="1191" alt="image"
src="https://github.com/user-attachments/assets/f143a6b1-abdf-4103-8041-cd6e1431c856"
/>
2026-06-26 12:34:36 -07:00
Paweł Banaszewski c15d483863 chore: rename 'last_used_at' column (#26749)
Renames the `last_used_at` column  to `last_heartbeat_at` in `ai_gateway_keys` table.  
`ai_gateway_keys` table has not been released yet.  
All references updated.
2026-06-26 18:45:37 +02:00
Paweł Banaszewski 6189d6e386 feat: add /api/v2/aibridge/serve endpoint (#26506)
Adds a new enterprise-only `GET /api/v2/ai-gateway/serve` endpoint that standalone AI Gateway replicas use to connect to `coderd` over a DRPC-over-WebSocket transport, mirroring the existing in-memory path used by the embedded AI Bridge daemon.

- The endpoint upgrades the HTTP connection to a WebSocket, multiplexes it with yamux, and finally serves the three DRPC services (Recorder, MCPConfigurator, Authorizer).
- The `X-AI-Governance-Gateway-Key` header is used for authentication.
    - The key is looked up by its hashed secret
    - Missing or revoked keys return `401`.
- API version negotiation is enforced via a new `aibridged/proto` version (`v1.0`).
    - Incompatible versions return `400`.
- `FeatureAIBridge` entitlement is required.
- Key liveness (`last_used_at`) is recorded immediately on connection and refreshed every 60 seconds while the session remains open.
  - When key liveness detects the key was deleted (no rows where updated) session is closed.

#### Small refactors

* The three DRPC service registrations are extracted into `aibridgedserver.Register`, shared by both the in-memory and WebSocket paths.

* The literal `256 * 1024` used as the yamux-aligned WebSocket read limit is replaced with the named constant `drpcsdk.YamuxDefaultStreamWindowSize` in all call sites.
  * as noted in review comment https://github.com/coder/coder/pull/26506#discussion_r3461905223 order of `SetReadLimit` and `WebsocketNetConn` calls was fixed.
2026-06-26 18:27:37 +02:00
Steven Masley ad355aeaa9 feat: add INSECURE oidc email fallback flag for IdP brokers (#26751)
<!-- Authored by Coder Agents on behalf of @Emyrk. -->

Adds an opt-in `CODER_DANGEROUS_OIDC_EMAIL_FALLBACK` flag (alias
`--dangerous-oidc-email-fallback`) for IdP brokers that do not issue a
stable `sub` for the same user across connections.
2026-06-26 11:23:42 -05:00
Paweł Banaszewski 0f1e792f3f feat(coderd/database): add AI Gateway key auth lookup and last-used queries (#26505)
Adds DB methods`GetAIGatewayKeyIDByHashedSecret` and `UpdateAIGatewayKeyLastUsedAt`.
`GetAIGatewayKeyIDByHashedSecret` - returns AI Gateway key ID by hashed secret value.
`UpdateAIGatewayKeyLastUsedAt` - updates last used timestamp for given AI Gateway key. 
Used by standalone AI Gateway for authentication and keeping track of currently used keys.
2026-06-26 18:16:01 +02:00
Spike Curtis 98e1ce133c chore: modify replicasync to handle NATS explicitly (#26666)
relates to GRU-69

Modifies replicasync to handle discovering NATS enabled primary replicas explicitly, and passing that info to the NATS Pubsub.

This PR adds a new deployment value to explicitly represent the host or IP that the replica can be reached on. It isn't wired up to the CLI, but piggybacks on the DERP config for now.

We learn the NATS port directly from NATS at runtime, and propagate it thru replicasync to learn all peers for clustering.
2026-06-26 08:36:32 -04:00
Mathias Fredriksson 59fcc9c0ad feat: improve sub-agent orchestration tools (#26673)
Tool errors caused orchestrators to abandon spawned agents. Bare error
responses and the close_agent name framed delegation as one-shot: one
transient failure or timeout ended the work, and the orchestrator had no
way to recover or reuse agents.

Renames close_agent to interrupt_agent with a hidden backward-compatible
alias. wait_agent and message_agent return structured payloads instead
of bare errors, so the orchestrator can retry after a timeout, recover
from an error status, or redirect an idle agent. Adds list_agents so
orchestrators can rediscover spawned agents. Adds root-only
orchestration guidance for error recovery.
2026-06-26 13:41:43 +03:00
Kyle Carberry a163d43981 fix(site/src/pages/AgentsPage): keep agent chat sticky truncation in sync as the transcript grows (#26714)
## Problem

In `/agents`, the sticky user-message truncation sometimes does not
update as new content arrives. While pinned to the bottom with the
transcript overflowing, several messages (or a streaming response) can
land and the sticky bubble keeps a stale clip height, overflowing and
overlapping the content below it. It only snaps back once you scroll
manually.

## Root cause

`StickyUserMessage` recomputes its clip height (`--clip-h`) and push-up
`top` in an `update()` driven by three triggers: a scroll listener, a
window-resize listener, and a `ResizeObserver` meant to catch the
transcript growing.

The observer watched `scroller.firstElementChild`, but in
`ChatScrollContainer` the scroller's first child is the `flex-1 basis-0`
spacer that pins content to the bottom, not the content wrapper. That
spacer collapses to `0px` the moment the transcript overflows (exactly
when truncation engages) and then never resizes again, so the observer
goes silent.

The other triggers do not cover this case either: in `flex-col-reverse`
the `scrollTop` stays at `0` while pinned to the bottom, so no scroll
event fires as content grows. The result is a stale `--clip-h` until the
next manual scroll.

## Fix

- Observe the real content wrapper instead of the collapsing spacer. The
wrapper is tagged with `data-chat-scroll-content` (it contains both the
committed timeline and the streaming live tail), and the sticky code
resolves it via `sentinel.closest(...)`, falling back to the previous
node only if the marker is absent.
- Recompute the scroller geometry (`scrollerTop`/`scrollerHeight`)
inside `update()` on every tick instead of caching it at effect setup,
so the clip and push-up math cannot drift when the scroller moves or
resizes without a window resize (for example the composer growing). This
also removes the now-redundant `onResize` handler.

No change to the sticky visuals or the rAF throttling.

## Testing

- New story `StickyUserMessageClipUpdatesWhilePinned` grows the
transcript while pinned (no scroll dispatched) and asserts the clip
tracks the new geometry, plus structural guards that the observed node
is the content marker and not the `aria-hidden` spacer.
- Verified as a true regression guard: with the fix reverted the new
story fails; with the fix it passes. The existing
`StickyUserMessagePinsOnScroll` is unaffected.
- `biome check`, `tsc -p .`, React Compiler check, emdash check, and
`vitest --project=storybook` for this stories file all pass (48/48).

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

- Considered centralizing the per-message scroll/resize/observer wiring
into a single coordinator in `ConversationTimeline` (it already
centralizes sentinels) to cut N observers/listeners down to one.
Deferred as a follow-up to keep this PR a surgical, low-risk fix; this
change alone resolves the staleness.
- Chose a semantic `data-chat-scroll-content` marker over reusing the
`chat-timeline-wrapper` test id so runtime behavior does not depend on a
test-only attribute. The marker sits on the wrapper that contains both
the timeline and the live tail, so streaming growth is observed too.
- Kept the `scroller.firstElementChild` fallback so other
`ConversationTimeline` consumers and stories without the marker keep
working.

</details>

---

Filed via Coder Agents on behalf of @kylecarbs.
2026-06-25 17:57:28 -06:00
Andrew Aquino 37d8b5163d feat(site): add search + filter tabs for template builder modules (#26674)
ref DEVEX-491

Adds a `useFuzzySearch` hook based on the logic in IconsPage.tsx, and
Storybook stories for `ModuleSelectStep` to verify filter tab count
behavior.

c16e0d9516 and
b6ee21875c co-written with Claude Code
2026-06-25 13:44:42 -07:00
uzair-coder07 7e509e8fd0 fix(site/src/pages/WorkspacesPage): show only parent agent apps in workspaces table (#26568)
The workspaces table shortcuts row selected `resources[0].agents[0]`, so
a sub-agent that ended up first (for example the Claude/Task sub-agent
created on a workspace) could replace the parent agent's launcher icons,
and which apps showed depended on agent ordering.

Select the parent agent (`parent_id === null`) of the first non-hidden
resource instead, matching the convention already used on the workspace
detail page (`Workspace.tsx`). This keeps the shortcuts row
deterministic and excludes sub-agent apps.

Refs
[DEVEX-459](https://linear.app/codercom/issue/DEVEX-459/aggregate-workspace-table-shortcuts-across-all-agents)

<details>
<summary>Decision context and scope</summary>

Per the discussion on DEVEX-459, this is the agreed short-term fix:

> In the short term, we should display only apps from the parent agent
and make the behavior deterministic, rather than the current reported
behavior of showing apps from the first discovered agent.

Out of scope (tracked as a longer-term backlog item on DEVEX-459):

- Aggregating app shortcuts across multiple agents.
- Changing the 4-slot cap (`WORKSPACE_APPS_SLOTS`).

For workspaces with multiple top-level agents, the first parent agent's
apps are shown. This is deterministic but not aggregated.

A `ParentAgentApps` Storybook story was added (sub-agent listed first)
with a `play` function asserting the parent agent's app renders and the
sub-agent's app does not.

</details>

---

This PR was created by Coder Agents on behalf of @uzair-coder07.
2026-06-25 15:39:27 -05:00
McKayla はな 4c8c496979 fix(site): add bottom padding to create workspace page (#26431) 2026-06-25 13:19:53 -06:00
Andrew Aquino 973056dcf6 feat(site): limit dropdown module config fields to 50% width (#26682)
closes DEVEX-532

## other changes

just cleaning up typographic styles a bit to match Figma better

- create `TemplateBuilderTitle`/`TemplateBuilderSubtitle` components for
h2+p elements at the top of steps
- left-align switch's description with its label
2026-06-25 10:49:46 -07:00
Danielle Maywood b40923d1dd fix(site): hide empty model provider configuration (#26690) 2026-06-25 15:17:04 +01:00