feat(studio): create duplicate guardrail - #1157
Conversation
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>
- 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>
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>
…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>
Signed-off-by: Alex Ray <alray@nvidia.com>
…reation-flow Signed-off-by: Alex Ray <alray@nvidia.com>
Signed-off-by: Alex Ray <alray@nvidia.com>
…reation-flow Signed-off-by: Alex Ray <alray@nvidia.com>
…ails-duplicate Signed-off-by: Alex Ray <alray@nvidia.com>
…uplicate Signed-off-by: Alex Ray <alray@nvidia.com>
📝 WalkthroughWalkthroughGuardrails can now be duplicated from list and detail views. The modal preloads copied configuration data, derives a length-constrained ChangesGuardrail duplication
Sequence Diagram(s)sequenceDiagram
participant User
participant GuardrailsDataView
participant GuardrailsRoute
participant CreateGuardrailModal
participant CreateMutation
User->>GuardrailsDataView: Select Duplicate
GuardrailsDataView->>GuardrailsRoute: Send selected GuardrailConfig
GuardrailsRoute->>CreateGuardrailModal: Open with sourceConfig
CreateGuardrailModal->>CreateGuardrailModal: Build copied name and preload fields
User->>CreateGuardrailModal: Submit duplicate
CreateGuardrailModal->>CreateMutation: Create copied guardrail
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
web/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.tsx (1)
94-103: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low valueUse a complete
GuardrailConfigfixture.SOURCE_CONFIGomits required response fields and usesas unknown as GuardrailConfig. Add the required fields instead. Bothdataschemas allow arbitrary object properties, so no production mapper or output-only-field assertion is needed.🤖 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/CreateGuardrailModal/index.tsx` around lines 94 - 103, Replace the incomplete SOURCE_CONFIG fixture in CreateGuardrailModal/index.test.tsx (lines 20-25) with a complete GuardrailConfig containing all required response fields, removing the unknown cast. Keep the onSubmit payload mapping in CreateGuardrailModal/index.tsx (lines 94-103) unchanged; both data schemas already permit the fixture’s arbitrary properties.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/components/dataViews/GuardrailsDataView/index.tsx`:
- Around line 24-28: Conditionally render the duplicate action in
GuardrailsDataView based on the optional onRequestDuplicate prop, so no
duplicate control appears when the handler is absent. Preserve the existing
action behavior when the handler is provided, and apply the same conditional
handling to the corresponding duplicate action instance noted in the comment.
---
Nitpick comments:
In `@web/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.tsx`:
- Around line 94-103: Replace the incomplete SOURCE_CONFIG fixture in
CreateGuardrailModal/index.test.tsx (lines 20-25) with a complete
GuardrailConfig containing all required response fields, removing the unknown
cast. Keep the onSubmit payload mapping in CreateGuardrailModal/index.tsx (lines
94-103) unchanged; both data schemas already permit the fixture’s arbitrary
properties.
🪄 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: 0428dff5-a061-47cf-b443-26a4bcd27208
📒 Files selected for processing (5)
web/packages/studio/src/components/dataViews/GuardrailsDataView/index.tsxweb/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.test.tsxweb/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.tsxweb/packages/studio/src/routes/guardrails/GuardrailDetailRoute/GuardrailDetailActions.tsxweb/packages/studio/src/routes/guardrails/GuardrailsRoute/index.tsx
|
…uplicate Signed-off-by: Alex Ray <alray@nvidia.com>
Move the guardrail duplicate-name logic out of CreateGuardrailModal into
`toCopyName` in @nemo/common/src/utils/entityName, alongside the
ENTITY_NAME_MAX_LENGTH constant and name sanitizers it depends on.
Two fixes fall out of sharing it:
- Truncating at MAX - len('-copy') could land just after a hyphen and
produce `my-guardrail--copy`, which ENTITY_NAME_REGEXP rejects for
consecutive hyphens. Trailing hyphens are now stripped first.
- The Data Designer clone path had its own CLONE_NAME_SUFFIX and never
truncated, so a 60-character job name cloned to 65 and failed
validation. buildClonedJobRequest now uses the shared helper.
Also type the CreateGuardrailModal test fixture as a full GuardrailConfig
instead of casting through `unknown`, and use an NVIDIA NemoGuard model in
the example rails config.
Signed-off-by: Alex Ray <alray@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/common/src/utils/entityName.ts`:
- Around line 42-55: The toCopyName function can return the original name when a
maximum-length source already ends with the copy suffix. Ensure the generated
candidate always differs from name by shortening the base or applying another
deterministic valid fallback, while preserving length and naming constraints;
add a regression test in the entityName tests for 58 “a” characters followed by
“-copy”.
🪄 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: 3bfb72b1-6fd6-41f6-ad64-592660b6f132
📒 Files selected for processing (6)
web/packages/common/src/utils/entityName.test.tsweb/packages/common/src/utils/entityName.tsweb/packages/studio/src/components/NewDataDesignerJobForm/utils.test.tsweb/packages/studio/src/components/NewDataDesignerJobForm/utils.tsweb/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.test.tsxweb/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- web/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.test.tsx
- web/packages/studio/src/routes/guardrails/CreateGuardrailModal/index.tsx
Screen.Recording.2026-08-07.at.2.48.41.PM.mov
Summary by CodeRabbit
New Features
Tests