Skip to content

feat(studio): add guardrail creation flow - #1115

Merged
aray12 merged 8 commits into
mainfrom
astd-341-guardrails-creation-flow
Aug 7, 2026
Merged

feat(studio): add guardrail creation flow#1115
aray12 merged 8 commits into
mainfrom
astd-341-guardrails-creation-flow

Conversation

@aray12

@aray12 aray12 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Screen.Recording.2026-08-06.at.12.20.57.PM.mov

Adds guardrail creation to Studio.

  • Create Guardrail button in the guardrails list page header opens a modal
  • Modal takes a single Name field, POSTs to the guardrails API, then redirects to the new guardrail's detail page
  • Name validation uses the shared entityNameSchema helper, so invalid names are caught client-side before the request goes out and the field shows the same guidance as other entity-name inputs
  • The name input opts out of browser autocomplete, autocorrect, autocapitalize, and spellcheck, since it's an identifier rather than prose
  • On success the workspace's config list query is invalidated, so the list is current when the user navigates back
  • Adds an MSW mock POST handler for local development

The modal is driven by local state in GuardrailsRoute rather than a route of its own. An earlier revision put it behind a /guardrails/new sub-path to make the flow linkable, but a guardrail literally named new would then be unreachable, and the extra history entry sat between the detail page and the list on back-navigation. Neither was worth the linkability for a transient two-field modal.

It lives at GuardrailsRoute/CreateGuardrailModal, matching how CreateSecretModal sits under SecretsListRoute.

Test plan

  • Click Create Guardrail — modal opens
  • Enter a name with uppercase letters — inline validation error, Create stays disabled
  • Enter a valid name — Create enables
  • Submit — modal closes, redirected to the new guardrail's detail page
  • Click browser back — lands on the guardrails list, with the new guardrail present
  • Cancel — modal closes, list unchanged

Summary by CodeRabbit

  • New Features

    • Added a “Create Guardrail” action to the Guardrails page.
    • Added a form for naming and creating guardrail configurations.
    • Automatically opens the newly created guardrail’s details after successful creation.
    • Displays validation and API conflict errors without closing the form.
  • Bug Fixes

    • Improved form reset and input focus behavior when opening or closing the creation dialog.

Adds a "Create Guardrail" button to the guardrails list header that
navigates to /guardrails/new, where a modal lets the user name the
guardrail and POST it to the API before redirecting to the detail route.

Client-side validation matches the backend name pattern
(^[a-z](?!.*--)[a-z0-9\-@.+_]{1,62}(?<!-)$) so invalid names are
caught before the API is called. Input attributes suppress browser
autocomplete and autocorrect for the identifier field.

Signed-off-by: Alex Ray <alray@nvidia.com>
@aray12
aray12 requested review from a team as code owners August 5, 2026 22:29
@github-actions github-actions Bot added the feat label Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

Guardrail creation

Layer / File(s) Summary
Creation form and submission
web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx, web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.test.tsx
The modal validates names, submits guardrail data, handles API errors, invalidates queries, closes on success, and navigates to the created guardrail. Tests cover success, failure, and validation.
Mock creation endpoint
web/packages/studio/src/mocks/handlers/guardrails.ts
The MSW handler creates and stores a guardrail configuration with generated metadata and returns HTTP 201.
Route and page wiring
web/packages/studio/src/routes/guardrails/GuardrailsRoute/index.tsx
The page adds a “Create Guardrail” button, controls modal visibility, and renders the creation modal.

Sequence Diagram(s)

sequenceDiagram
  participant GuardrailsRoute
  participant CreateGuardrailModal
  participant MSWGuardrailHandler
  participant mockGuardrailConfigs
  GuardrailsRoute->>CreateGuardrailModal: Open creation modal
  CreateGuardrailModal->>MSWGuardrailHandler: Submit name and description
  MSWGuardrailHandler->>mockGuardrailConfigs: Store generated configuration
  MSWGuardrailHandler-->>CreateGuardrailModal: Return created configuration with HTTP 201
  CreateGuardrailModal->>GuardrailsRoute: Navigate to created guardrail
Loading

Possibly related PRs

Suggested reviewers: steramae-nvidia, nakolean

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the guardrail creation flow added to Studio.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch astd-341-guardrails-creation-flow

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
web/packages/studio/src/routes/utils.ts (1)

401-403: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add an explicit return type.

Add : string to this exported route helper.

As per coding guidelines, use explicit return types for public APIs and complex functions.

Proposed fix
-export const getGuardrailNewRoute = (workspace: string) => {
+export const getGuardrailNewRoute = (workspace: string): string => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/packages/studio/src/routes/utils.ts` around lines 401 - 403, Add the
explicit string return type to the exported getGuardrailNewRoute function,
preserving its existing generatePath implementation and behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/packages/studio/src/mocks/handlers/guardrails.ts`:
- Line 149: Remove the duplicate body declaration in the request handler,
keeping a single parsed request body variable with the existing { name: string;
description?: string } type used by the handler.

In `@web/packages/studio/src/routes/guardrails/GuardrailNewRoute/index.tsx`:
- Around line 58-66: Update the FormModal invocation in GuardrailNewRoute to
pass disabled={isPending}, preventing cancel and close actions while guardrail
creation is pending; leave the existing submitDisabled and loading behavior
unchanged.

---

Nitpick comments:
In `@web/packages/studio/src/routes/utils.ts`:
- Around line 401-403: Add the explicit string return type to the exported
getGuardrailNewRoute function, preserving its existing generatePath
implementation and behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 48327e31-c0c9-428f-8c9f-b6f8aea5de03

📥 Commits

Reviewing files that changed from the base of the PR and between 607acde and 7fd1cca.

📒 Files selected for processing (6)
  • web/packages/studio/src/constants/routes.ts
  • web/packages/studio/src/mocks/handlers/guardrails.ts
  • web/packages/studio/src/routes/groups/guardrailsRoutes.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailNewRoute/index.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/index.tsx
  • web/packages/studio/src/routes/utils.ts

Comment thread web/packages/studio/src/mocks/handlers/guardrails.ts Outdated
- Rename body to input in POST mock handler to avoid shadowing the PATCH
  handler's body variable in the same file scope
- Add disabled={isPending} to FormModal so the user cannot close or
  resubmit the modal while the create request is in flight

Signed-off-by: Alex Ray <alray@nvidia.com>
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 31438/40061 78.5% 63.0%
Integration Tests 18308/38013 48.2% 20.8%

aray12 added 2 commits August 6, 2026 10:17
Avoids a naming conflict where a guardrail named 'new' would be
unreachable via the UI. The ~ character is outside the backend name
pattern so /~new can never collide with a real guardrail name.

Signed-off-by: Alex Ray <alray@nvidia.com>
Drops the /~new sub-path entirely. The creation modal is now opened by
local state in GuardrailsRoute rather than a child route, so there is no
URL segment that can collide with a guardrail name and no history entry
to skip past when navigating back from the detail page.

Moves the component to GuardrailsRoute/CreateGuardrailModal, matching
the CreateSecretModal placement under SecretsListRoute.

Signed-off-by: Alex Ray <alray@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx (1)

18-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename the schema constant.

Rename schema to SCHEMA. Update its references.

Proposed fix
-const schema = z.object({
+const SCHEMA = z.object({
   name: entityNameSchema(),
 });

-type FormData = z.infer<typeof schema>;
+type FormData = z.infer<typeof SCHEMA>;

As per coding guidelines: “Use SCREAMING_SNAKE_CASE for constants.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx`
around lines 18 - 22, Rename the `schema` constant to `SCHEMA` in the guardrail
modal and update all references, including the `FormData` type inference, while
preserving its existing validation behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx`:
- Around line 58-59: Update the onSubmit handler to catch only the createConfig
mutation rejection, assign the mutation error to errorText, and return before
continuing the success path so the rejected promise cannot escape FormModal. Add
a rejected-POST test for the guardrail creation flow that verifies no unhandled
rejection and visible error text.

---

Nitpick comments:
In
`@web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx`:
- Around line 18-22: Rename the `schema` constant to `SCHEMA` in the guardrail
modal and update all references, including the `FormData` type inference, while
preserving its existing validation behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: cdd49329-8fe1-4a04-9884-2c2b2df76c60

📥 Commits

Reviewing files that changed from the base of the PR and between 236b828 and 3ceaaf7.

📒 Files selected for processing (2)
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/index.tsx

…ection

react-hook-form re-throws from its submit handler and FormModal drops the
returned promise, so a rejected POST surfaced as an unhandled rejection.
The user already saw the failure via errorText, but the rejection escaped
and turned the test run red. Catch it and return, matching CreateSecretModal.

Also renames the zod schema to createGuardrailFormSchema to match the
naming used by sibling form modals, and adds tests covering the success
path, the failed-create path, and client-side name validation.

Signed-off-by: Alex Ray <alray@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.test.tsx (2)

50-53: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert query invalidation after creation.

The success test checks navigation and onClose, but not queryClient.invalidateQueries. A regression can leave the guardrails list stale while this test passes. Return the QueryClient from renderModal, spy on invalidateQueries, and assert the workspace config query key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.test.tsx`
around lines 50 - 53, Update the success test around renderModal to expose its
QueryClient, spy on queryClient.invalidateQueries, and assert it is called with
the workspace configuration query key after guardrail creation. Preserve the
existing navigation and onClose assertions.

41-43: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert the POST payload in both MSW handlers.

Both handlers return fixed responses without reading request. The tests pass even if CreateGuardrailModal sends the wrong name. Parse the request body and assert { name: 'my-rail' }.

Suggested assertion
-      http.post(CONFIGS_URL, () =>
-        HttpResponse.json({ name: 'my-rail' }, { status: 201 })
-      )
+      http.post(CONFIGS_URL, async ({ request }) => {
+        expect(await request.json()).toEqual({ name: 'my-rail' });
+        return HttpResponse.json({ name: 'my-rail' }, { status: 201 });
+      })

Also applies to: 57-61

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.test.tsx`
around lines 41 - 43, Update both MSW POST handlers in the CreateGuardrailModal
tests to accept the request, parse its JSON body, and assert that the payload
equals { name: 'my-rail' } before returning the existing responses. Apply this
to the handlers around both referenced test sections.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.test.tsx`:
- Around line 50-53: Update the success test around renderModal to expose its
QueryClient, spy on queryClient.invalidateQueries, and assert it is called with
the workspace configuration query key after guardrail creation. Preserve the
existing navigation and onClose assertions.
- Around line 41-43: Update both MSW POST handlers in the CreateGuardrailModal
tests to accept the request, parse its JSON body, and assert that the payload
equals { name: 'my-rail' } before returning the existing responses. Apply this
to the handlers around both referenced test sections.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 328418d3-4887-429e-a46f-b0686b0048bf

📥 Commits

Reviewing files that changed from the base of the PR and between 3ceaaf7 and 6a63623.

📒 Files selected for processing (2)
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.test.tsx
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/packages/studio/src/routes/guardrails/GuardrailsRoute/CreateGuardrailModal/index.tsx

@aray12
aray12 enabled auto-merge August 6, 2026 19:47
aray12 added 3 commits August 6, 2026 15:31
Signed-off-by: Alex Ray <alray@nvidia.com>
…reation-flow

Signed-off-by: Alex Ray <alray@nvidia.com>
…reation-flow

Signed-off-by: Alex Ray <alray@nvidia.com>
@aray12
aray12 added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit c85f1c2 Aug 7, 2026
51 of 52 checks passed
@aray12
aray12 deleted the astd-341-guardrails-creation-flow branch August 7, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants